mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 10:47:04 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1558b69931 | ||
|
|
a560a3d3ae | ||
|
|
b620110d0f | ||
|
|
23ea72bf40 | ||
|
|
aaee0b7965 | ||
|
|
347523f9e7 | ||
|
|
3205630a0f | ||
|
|
8446e3fbbd | ||
|
|
6d25a97fc8 | ||
|
|
bdbfce0e18 | ||
|
|
8033e8f7cc | ||
|
|
f98c801d6c | ||
|
|
339663adaf | ||
|
|
2b15357dee | ||
|
|
1e05717daf | ||
|
|
c20f8c5040 | ||
|
|
f22f4eeccd | ||
|
|
79c450798c | ||
|
|
d247e67690 | ||
|
|
69b2035cfc | ||
|
|
62fed63310 | ||
|
|
7c29046390 | ||
|
|
b65c3c1d93 | ||
|
|
87f5d8fe8f | ||
|
|
54c7b6b476 | ||
|
|
7bdaf9ca93 | ||
|
|
525b9377cc | ||
|
|
94cba0c9ba | ||
|
|
4ddf77fc7f | ||
|
|
ae6dc259dc | ||
|
|
c2e95f6ef6 | ||
|
|
868812e578 | ||
|
|
b5064f9e8b | ||
|
|
a0eb0d54f0 | ||
|
|
e47b1315a9 | ||
|
|
60025365c4 | ||
|
|
cde6904513 | ||
|
|
997d1df8f9 | ||
|
|
9f15ded0c9 | ||
|
|
b2ee97b3d4 | ||
|
|
03d819a6c1 | ||
|
|
8ff26d57f6 | ||
|
|
c243ebd19a | ||
|
|
40f5042896 | ||
|
|
21130b29f8 | ||
|
|
d50b054243 | ||
|
|
6b7f8049fe | ||
|
|
e6029157aa | ||
|
|
ba656eb603 | ||
|
|
e8dd26b2ba | ||
|
|
897da9479d | ||
|
|
291395718f | ||
|
|
42e860b171 | ||
|
|
3b6d339310 | ||
|
|
728fd5b824 | ||
|
|
34217b2754 | ||
|
|
1e7acc2775 | ||
|
|
0b5c88531f | ||
|
|
e145d7c6e8 | ||
|
|
af13e3f184 | ||
|
|
19a2492555 | ||
|
|
3c51f4f94a | ||
|
|
86f4712b87 | ||
|
|
ea90ca21b1 | ||
|
|
b3046d8655 | ||
|
|
8f9e537a5e | ||
|
|
9368d058f2 | ||
|
|
31b628049a | ||
|
|
072e913433 | ||
|
|
e3f131cdfd | ||
|
|
5cab394ced | ||
|
|
2033fab21a | ||
|
|
7471567147 | ||
|
|
43aee373ea | ||
|
|
993083665b | ||
|
|
f2c25424d9 | ||
|
|
bbe53deb98 | ||
|
|
1f07c2be74 | ||
|
|
ea744b673a | ||
|
|
d8a6cac52f | ||
|
|
1524b9a35d | ||
|
|
36738f57a9 | ||
|
|
fca6cb23d1 | ||
|
|
a704b291fd | ||
|
|
e1b5b21fae | ||
|
|
097f2792ae | ||
|
|
089d0e9682 | ||
|
|
6a92b3ae80 | ||
|
|
1e91065033 | ||
|
|
b20bb97ea3 | ||
|
|
ba97a9f28b | ||
|
|
81e480f983 | ||
|
|
40e4e0a274 | ||
|
|
83b7de77de | ||
|
|
20f7119854 | ||
|
|
275ddcc7a6 | ||
|
|
4858f31da4 | ||
|
|
4bc255a624 | ||
|
|
17755641a1 | ||
|
|
0e6b0087ce | ||
|
|
fcd084a86f | ||
|
|
af699ff5b7 | ||
|
|
93665df223 | ||
|
|
f8b4f9372a | ||
|
|
e84e15daf4 | ||
|
|
d7af7e19dd | ||
|
|
c5cf172e42 | ||
|
|
2e8cac885c | ||
|
|
9ed4a856bf | ||
|
|
eedd4b3f27 | ||
|
|
3b7fe0b114 | ||
|
|
a6d66b94f5 | ||
|
|
c7a7bbb809 | ||
|
|
02ce6ba8d9 | ||
|
|
9dd057d594 | ||
|
|
64ec981496 | ||
|
|
8afafdeece | ||
|
|
6b9fd1d392 | ||
|
|
c1efc50134 | ||
|
|
b4b1f4e916 | ||
|
|
3de0c40ce3 | ||
|
|
893bfa8393 | ||
|
|
cc25535c34 | ||
|
|
a4cdf16fcd | ||
|
|
36588b11e6 | ||
|
|
e927838c14 | ||
|
|
5197ebb6a7 | ||
|
|
51089a3e91 | ||
|
|
c6121fd4bd | ||
|
|
7dca9d3244 | ||
|
|
abebfcf6c6 | ||
|
|
470869418c | ||
|
|
cd2bad3b27 | ||
|
|
5e9555aa57 | ||
|
|
084d55b853 | ||
|
|
a3879f3fa7 | ||
|
|
135a2d74c4 | ||
|
|
233f866c9e | ||
|
|
9e880ff24f | ||
|
|
36039563e0 | ||
|
|
022e970537 | ||
|
|
51e99ec442 | ||
|
|
caeba34ba1 | ||
|
|
6d6a634973 | ||
|
|
55e6599eaa | ||
|
|
e146366385 | ||
|
|
b1dd319c1e | ||
|
|
e7ca8f1b10 | ||
|
|
0d8a677ac5 | ||
|
|
a8dc271e0a | ||
|
|
f3d6ba68a7 | ||
|
|
e68b27bac4 | ||
|
|
d49eef7308 | ||
|
|
6e630a91aa | ||
|
|
2c66e79daf | ||
|
|
9a94a4e371 | ||
|
|
b1372c998d | ||
|
|
4ed93cb38f | ||
|
|
4d1b175c07 | ||
|
|
ecfedc32ad | ||
|
|
9da514c329 | ||
|
|
ee5386c925 | ||
|
|
1a90e9312d | ||
|
|
2c7082fe04 | ||
|
|
518a83ee73 | ||
|
|
25c40bcea2 | ||
|
|
f88ac8daf7 | ||
|
|
c4be6b78b6 | ||
|
|
2cfc65a990 | ||
|
|
a8eb751048 | ||
|
|
f030fd53b1 | ||
|
|
da506083c9 | ||
|
|
8bdc4d9b1b | ||
|
|
e0718d9ebb | ||
|
|
dbf1718d39 | ||
|
|
84dd13c0ac | ||
|
|
fdecef5f9c | ||
|
|
198e800958 | ||
|
|
29bb8ada06 | ||
|
|
662f116afe | ||
|
|
02f0c078a5 | ||
|
|
4dd1113b6d | ||
|
|
e656b83719 | ||
|
|
b90b355f8f | ||
|
|
165a9cd719 | ||
|
|
5b8da36fb8 | ||
|
|
bbe682fa73 | ||
|
|
af08df1526 | ||
|
|
47a60adac7 | ||
|
|
10f3bc0026 | ||
|
|
e7da1d582f | ||
|
|
df70816f7e | ||
|
|
091364d7f3 | ||
|
|
753c06eee8 | ||
|
|
17713243b5 | ||
|
|
4e4f070368 | ||
|
|
4064f163ec | ||
|
|
b911f64847 | ||
|
|
b86b6e09d0 | ||
|
|
d2e7a477bb | ||
|
|
f9c182e68c | ||
|
|
7c497ab681 | ||
|
|
c840086c11 | ||
|
|
8649d09a94 | ||
|
|
c764564a96 | ||
|
|
ad8cbb96b7 | ||
|
|
b409e26ca5 | ||
|
|
fbbfa5307c | ||
|
|
4165533838 | ||
|
|
fb47ab3e64 | ||
|
|
57971453ad | ||
|
|
c8cb490b48 | ||
|
|
232f24181f | ||
|
|
46441d74d8 | ||
|
|
a2274a6f0c | ||
|
|
0eb2827e7b | ||
|
|
41cb3f8511 | ||
|
|
9405dccee9 | ||
|
|
83b0c6abc3 | ||
|
|
bf1621001b | ||
|
|
8a5a4bf696 | ||
|
|
a99cce07dc | ||
|
|
d8c26ba24a | ||
|
|
f0b393c48f | ||
|
|
d0d205bb93 | ||
|
|
aeaf52d3ac | ||
|
|
e05358952a | ||
|
|
c1000e1608 | ||
|
|
46c86c5352 | ||
|
|
507b503560 | ||
|
|
37ca981d33 | ||
|
|
efe6d2b1a5 | ||
|
|
9f79f9c1e8 | ||
|
|
38b4c62777 | ||
|
|
df1bc56a4c | ||
|
|
c3d2b063bc | ||
|
|
1b94748668 | ||
|
|
f4f804727f | ||
|
|
3729072594 | ||
|
|
c174f32e15 | ||
|
|
2443ecde2f | ||
|
|
9c027b3dde | ||
|
|
22d794ac65 | ||
|
|
35073c184e | ||
|
|
4741406e4a | ||
|
|
24107433c6 | ||
|
|
05c6fcfb34 | ||
|
|
be7a16d399 | ||
|
|
c7f781dbb2 | ||
|
|
a66c6ebb27 | ||
|
|
83aeca2e5e | ||
|
|
89a3db05d8 | ||
|
|
6050145b16 | ||
|
|
77c78741b3 | ||
|
|
f35670d6a8 | ||
|
|
3392a57480 | ||
|
|
ed64ee8228 | ||
|
|
4f47d6ce85 | ||
|
|
92d56ac086 | ||
|
|
671b8b60b9 | ||
|
|
ba5a5245d9 | ||
|
|
eee262add7 | ||
|
|
e5eaf3fd75 | ||
|
|
5fdc9044ca | ||
|
|
0924a77776 | ||
|
|
1a46e176f5 | ||
|
|
efb8df9769 | ||
|
|
04e09b84ff | ||
|
|
b52c107af9 | ||
|
|
c5e6f5e2eb | ||
|
|
365c68aa4d | ||
|
|
ff9ec55da6 | ||
|
|
2a2994ae69 | ||
|
|
e3c6497d29 | ||
|
|
bdc013b4c8 | ||
|
|
e20d65d218 | ||
|
|
8b726c12d9 | ||
|
|
da704e6181 | ||
|
|
64d346ccb6 | ||
|
|
c090ad6492 | ||
|
|
8b6610151e | ||
|
|
545b655d4e | ||
|
|
0e6aa734cb | ||
|
|
2bef96475c | ||
|
|
45938c875f | ||
|
|
9d916a588d | ||
|
|
f0295079cc | ||
|
|
6d8387fa9d | ||
|
|
7a18de6650 | ||
|
|
cc6c4faa2d | ||
|
|
4253cd3e1b | ||
|
|
75cf827082 | ||
|
|
73c8807f14 | ||
|
|
9fac6dd40d | ||
|
|
c06c338536 | ||
|
|
9258623931 | ||
|
|
3b02c25973 | ||
|
|
f90768d155 | ||
|
|
d77bd6a5f9 | ||
|
|
6836cb327f | ||
|
|
4373efd0cd | ||
|
|
f13165e77d | ||
|
|
8a5b0c1170 | ||
|
|
f16511a72e | ||
|
|
76f7ae45ce | ||
|
|
ad2aaa7bf8 | ||
|
|
2a4375c718 | ||
|
|
df0dc4f118 | ||
|
|
92399de5e2 | ||
|
|
8d9dff8d73 | ||
|
|
f91744f2f0 | ||
|
|
e946dfdb69 | ||
|
|
6283ddc57a | ||
|
|
2d66e0ab28 | ||
|
|
c3d8f15a2a | ||
|
|
21a37ec6cc | ||
|
|
de471400ad | ||
|
|
0b16295853 | ||
|
|
63eea81856 | ||
|
|
ba57d61af5 | ||
|
|
3d940f4b47 | ||
|
|
8ef355c574 | ||
|
|
71e1ab1362 | ||
|
|
53dc108356 | ||
|
|
57b3218c5a | ||
|
|
7472e39faf | ||
|
|
034417d19f | ||
|
|
0368e9ceda | ||
|
|
28f365f762 | ||
|
|
40a81f6b1b | ||
|
|
9475d22472 | ||
|
|
9538a03afb | ||
|
|
d5d171bea6 | ||
|
|
a9c9a90ac1 | ||
|
|
f7c562f8b6 | ||
|
|
836cf69f01 | ||
|
|
ba17aae706 | ||
|
|
30ca5c053a | ||
|
|
c36419f5b6 | ||
|
|
1879895db2 | ||
|
|
c964e3c8ec | ||
|
|
2ef6d18f82 | ||
|
|
10b672572b | ||
|
|
2a4efa8cd2 | ||
|
|
5a8435da29 | ||
|
|
3461349a96 | ||
|
|
3791e9df12 | ||
|
|
b3c36aac93 | ||
|
|
c0895409bc | ||
|
|
438b565cbb | ||
|
|
cf1a82e89b | ||
|
|
0506e361b2 | ||
|
|
d6a1357a82 | ||
|
|
a5a1dbd51b | ||
|
|
5201350e44 | ||
|
|
6a84b9d5ae | ||
|
|
cf04fe21b3 | ||
|
|
84eb3c2da3 | ||
|
|
22bf2dc1d8 | ||
|
|
b9c339daa7 | ||
|
|
ef3006cac1 | ||
|
|
e482fd40c1 | ||
|
|
cc4569966e | ||
|
|
3708a3ced7 | ||
|
|
0ae59c2fd7 | ||
|
|
7027f63236 | ||
|
|
6725e79021 | ||
|
|
5ca3cee9da | ||
|
|
602a5a1e99 | ||
|
|
bfbf3bdc39 | ||
|
|
644686582e | ||
|
|
1c00bc81f8 | ||
|
|
ac3b69bec5 | ||
|
|
3e14c943b6 | ||
|
|
d33633be2c | ||
|
|
4bf70d02d0 | ||
|
|
377bcf0e38 | ||
|
|
884b6d4318 | ||
|
|
ee94d762d0 | ||
|
|
bcde319ac1 | ||
|
|
a4828774ca | ||
|
|
e59725d763 | ||
|
|
a62179a853 | ||
|
|
38ba940a98 | ||
|
|
a07d6c775e | ||
|
|
f9f7468544 | ||
|
|
98724df711 | ||
|
|
5499cb5cca | ||
|
|
122b3f6478 | ||
|
|
d2b24fc953 | ||
|
|
bb557a7dd7 | ||
|
|
f1612e8fe3 | ||
|
|
d12f4fb00e | ||
|
|
ad555ece9a | ||
|
|
9aee8feaf4 | ||
|
|
baa16840df | ||
|
|
4e80490fd4 | ||
|
|
6233c16b88 | ||
|
|
c4f1d9f3b0 | ||
|
|
2c365cdea0 | ||
|
|
18afa4cd28 | ||
|
|
ef9778ea96 | ||
|
|
d8459d373c | ||
|
|
7900c61a9b | ||
|
|
ceb7842d49 | ||
|
|
e0c897025e | ||
|
|
ade6ec8af1 | ||
|
|
06cbe1e733 | ||
|
|
cb3e759f75 | ||
|
|
e4558d978c | ||
|
|
260d819c77 | ||
|
|
ffe58de179 | ||
|
|
6fbe1d6339 | ||
|
|
835d03d12c | ||
|
|
2b208fa6a0 | ||
|
|
66d63d5c60 | ||
|
|
134566f1d8 | ||
|
|
d592a95cae | ||
|
|
4f74556eb6 | ||
|
|
1342f434a3 | ||
|
|
6110471990 | ||
|
|
359eec5209 | ||
|
|
6ccffa0458 | ||
|
|
4c0c10e39e | ||
|
|
3d41c56c73 | ||
|
|
e0dda567f4 | ||
|
|
91b367cd70 | ||
|
|
5a65fee1d1 | ||
|
|
c7856364ad | ||
|
|
65899a06c4 | ||
|
|
571ae81306 | ||
|
|
6b2dda0f9d | ||
|
|
9de41529d1 | ||
|
|
7dfdf4c11b | ||
|
|
db4132f666 | ||
|
|
d9688f6051 | ||
|
|
12e89a6b65 | ||
|
|
2d524cd273 | ||
|
|
1d44ecab18 | ||
|
|
bf9addf589 | ||
|
|
4deee2d709 | ||
|
|
309fda1ed1 | ||
|
|
d6e7f35214 | ||
|
|
7cd9131b60 | ||
|
|
599b81934e | ||
|
|
3f595d0d8a | ||
|
|
9afed23bb8 | ||
|
|
fc869f8b45 | ||
|
|
cf7ba1c6b5 | ||
|
|
07ca41e82a | ||
|
|
c487d9af61 | ||
|
|
9be6725043 | ||
|
|
e0daf85561 | ||
|
|
8203db3dc2 | ||
|
|
eb5527706e | ||
|
|
1f577c2317 | ||
|
|
68362c22b1 | ||
|
|
844965bcb0 | ||
|
|
1843eb3bcf | ||
|
|
60ab845326 | ||
|
|
3bbc083b2a | ||
|
|
8df159b182 | ||
|
|
c7238b0342 | ||
|
|
ba6006a320 | ||
|
|
43b9252f21 | ||
|
|
d727ceaaf6 | ||
|
|
eb95230a5f | ||
|
|
b6fd5eaa66 | ||
|
|
117f9892d6 | ||
|
|
c20caf45a2 | ||
|
|
670b678348 | ||
|
|
b1f0d4d844 | ||
|
|
e9d1c82a60 | ||
|
|
cc4345f1a3 | ||
|
|
6d8326861b | ||
|
|
8517ecfdb6 | ||
|
|
a38b5d7ddd | ||
|
|
f726793819 | ||
|
|
19531aa9ae | ||
|
|
6d6bae847b | ||
|
|
cc70b3ccc3 | ||
|
|
e3bf619808 | ||
|
|
f6cb4f2518 | ||
|
|
f396d6c4a1 | ||
|
|
768c420ae4 | ||
|
|
7fba197bef | ||
|
|
b074481e1a | ||
|
|
987e35ef8f | ||
|
|
83c77b5945 | ||
|
|
e4f0120d67 | ||
|
|
2055c00154 | ||
|
|
c814230dcb | ||
|
|
2f31aadb29 | ||
|
|
3113bf3a47 | ||
|
|
70bd54e03b | ||
|
|
8863ac5fde | ||
|
|
b62009ce2b | ||
|
|
0f3d230f42 | ||
|
|
9db6b997c3 | ||
|
|
d9fcbd028b | ||
|
|
db74058075 | ||
|
|
4180736d37 | ||
|
|
382f04229e | ||
|
|
3c9ba9ec53 | ||
|
|
4848234264 | ||
|
|
2ad0fcfdf9 | ||
|
|
8f0894364b | ||
|
|
3695b8f7f4 | ||
|
|
4f8c1d416f | ||
|
|
453286677a | ||
|
|
53a49f199a | ||
|
|
fdfde46342 | ||
|
|
1d836b2053 | ||
|
|
6d448dc5c4 | ||
|
|
75d4d60b30 | ||
|
|
e7f47fd2fd | ||
|
|
2458d2c80c | ||
|
|
37a72e3bb5 | ||
|
|
415861f6e8 | ||
|
|
3124afa253 | ||
|
|
8523b9f44f | ||
|
|
71e0404890 | ||
|
|
c01fd1f4ff |
No files matched your search
@@ -37,8 +37,23 @@ env:
|
||||
WOTB_GLOSSARY: ${{ secrets.WOTB_GLOSSARY }}
|
||||
WOTB_DLC_CDN: ${{ secrets.WOTB_DLC_CDN }}
|
||||
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
||||
PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }}
|
||||
PUBLIC_ASSET_BRANCH: ${{ github.event.inputs.cdn_branch || secrets.PUBLIC_ASSET_BRANCH }}
|
||||
PUBLIC_ASSET_REPO: blitzkit/assets
|
||||
PUBLIC_ASSET_BRANCH: main
|
||||
WOTB_GLOSSARY_DOMAIN: ${{ secrets.WOTB_GLOSSARY_DOMAIN }}
|
||||
WOTB_GLOSSARY_PATH: ${{ secrets.WOTB_GLOSSARY_PATH }}
|
||||
PUBLIC_PROMOTE_OPENTEST: ${{ secrets.PUBLIC_PROMOTE_OPENTEST }}
|
||||
ALLOW_ROBOTS: true
|
||||
PUBLIC_GOOGLE_TAG_MANAGER_ID: ${{ secrets.PUBLIC_GOOGLE_TAG_MANAGER_ID }}
|
||||
PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ${{ secrets.PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID }}
|
||||
PUBLIC_PATREON_CLIENT_ID: ${{ secrets.PUBLIC_PATREON_CLIENT_ID }}
|
||||
PUBLIC_PATREON_REDIRECT_URI: ${{ secrets.PUBLIC_PATREON_REDIRECT_URI }}
|
||||
PATREON_CLIENT_SECRET: ${{ secrets.PATREON_CLIENT_SECRET }}
|
||||
PUBLIC_NITROPAY_ID: ${{ secrets.PUBLIC_NITROPAY_ID }}
|
||||
PUBLIC_DEBUG_MISSING_I18N: false
|
||||
PUBLIC_DISCORD_SERVER_ID: ${{ secrets.PUBLIC_DISCORD_SERVER_ID }}
|
||||
PUBLIC_ASSET_FAST_USER: blitzkit
|
||||
PUBLIC_ASSET_FAST_REPO: assets
|
||||
PUBLIC_ASSET_BASE: ${{ secrets.PUBLIC_ASSET_BASE }}
|
||||
|
||||
jobs:
|
||||
download_client:
|
||||
@@ -106,6 +121,9 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
submodules: recursive
|
||||
token: ${{ secrets.GH_TOKEN }}
|
||||
|
||||
- name: Setup bun
|
||||
uses: oven-sh/setup-bun@v1
|
||||
@@ -113,11 +131,23 @@ jobs:
|
||||
- name: Install dependencies
|
||||
run: bun install
|
||||
|
||||
- name: Lint
|
||||
run: bun run lint:website
|
||||
|
||||
- name: Download depots
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: depots
|
||||
path: depots
|
||||
|
||||
- name: Build assets
|
||||
run: bun run build:assets --all-targets --depot --production
|
||||
- name: AppArmor hack
|
||||
run: echo 0 | sudo tee /proc/sys/kernel/apparmor_restrict_unprivileged_userns
|
||||
|
||||
- name: Start server and build assets
|
||||
run: |
|
||||
bun dev:website --verbosepa &
|
||||
SERVER_PID=$!
|
||||
|
||||
bun run build:assets --all-targets --depot --production
|
||||
|
||||
kill $SERVER_PID || true
|
||||
@@ -12,6 +12,19 @@ concurrency:
|
||||
env:
|
||||
PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }}
|
||||
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
||||
PUBLIC_ASSET_FAST_USER: ${{ secrets.PUBLIC_ASSET_FAST_USER }}
|
||||
PUBLIC_ASSET_FAST_REPO: ${{ secrets.PUBLIC_ASSET_FAST_REPO }}
|
||||
PUBLIC_PROMOTE_OPENTEST: ${{ secrets.PUBLIC_PROMOTE_OPENTEST }}
|
||||
ALLOW_ROBOTS: 'true'
|
||||
WOTB_GLOSSARY: ${{ secrets.WOTB_GLOSSARY }}
|
||||
PUBLIC_GOOGLE_TAG_MANAGER_ID: ${{ secrets.PUBLIC_GOOGLE_TAG_MANAGER_ID }}
|
||||
PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ${{ secrets.PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID }}
|
||||
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
|
||||
WOTB_GLOSSARY_DOMAIN: ${{ secrets.WOTB_GLOSSARY_DOMAIN }}
|
||||
WOTB_GLOSSARY_PATH: ${{ secrets.WOTB_GLOSSARY_PATH }}
|
||||
PUBLIC_DISCORD_SERVER_ID: ${{ secrets.PUBLIC_DISCORD_SERVER_ID }}
|
||||
PUBLIC_ASSET_BASE: ${{ secrets.PUBLIC_ASSET_BASE }}
|
||||
PUBLIC_BRANCH: ${{ secrets.PUBLIC_BRANCH }}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
@@ -20,6 +20,8 @@ env:
|
||||
PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }}
|
||||
PUBLIC_ASSET_BRANCH: ${{ secrets.PUBLIC_ASSET_BRANCH }}
|
||||
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
||||
PUBLIC_ASSET_FAST_USER: ${{ secrets.PUBLIC_ASSET_FAST_USER }}
|
||||
PUBLIC_ASSET_FAST_REPO: ${{ secrets.PUBLIC_ASSET_FAST_REPO }}
|
||||
|
||||
jobs:
|
||||
host:
|
||||
@@ -27,12 +29,12 @@ jobs:
|
||||
|
||||
steps:
|
||||
- uses: oven-sh/setup-bun@v1
|
||||
# with:
|
||||
# bun-version: 1.1.33
|
||||
# with:
|
||||
# bun-version: 1.1.33
|
||||
|
||||
- name: Download release assets
|
||||
run: |
|
||||
DOWNLOAD_URL=$(curl -s https://api.github.com/repos/tresabhi/blitzkit/releases/latest \
|
||||
DOWNLOAD_URL=$(curl -s https://api.github.com/repos/blitzkit/blitzkit/releases/latest \
|
||||
| grep "browser_download_url.*bot.zip" \
|
||||
| cut -d : -f 2,3 \
|
||||
| tr -d \")
|
||||
|
||||
@@ -25,4 +25,17 @@ jobs:
|
||||
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
||||
PUBLIC_ASSET_FAST_USER: ${{ secrets.PUBLIC_ASSET_FAST_USER }}
|
||||
PUBLIC_ASSET_FAST_REPO: ${{ secrets.PUBLIC_ASSET_FAST_REPO }}
|
||||
PUBLIC_PROMOTE_OPENTEST: ${{ secrets.PUBLIC_PROMOTE_OPENTEST }}
|
||||
ALLOW_ROBOTS: 'true'
|
||||
WOTB_GLOSSARY: ${{ secrets.WOTB_GLOSSARY }}
|
||||
PUBLIC_GOOGLE_TAG_MANAGER_ID: ${{ secrets.PUBLIC_GOOGLE_TAG_MANAGER_ID }}
|
||||
PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ${{ secrets.PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID }}
|
||||
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
|
||||
WOTB_GLOSSARY_DOMAIN: ${{ secrets.WOTB_GLOSSARY_DOMAIN }}
|
||||
WOTB_GLOSSARY_PATH: ${{ secrets.WOTB_GLOSSARY_PATH }}
|
||||
PUBLIC_DISCORD_SERVER_ID: ${{ secrets.PUBLIC_DISCORD_SERVER_ID }}
|
||||
PUBLIC_ASSET_BASE: ${{ secrets.PUBLIC_ASSET_BASE }}
|
||||
PUBLIC_BRANCH: ${{ secrets.PUBLIC_BRANCH }}
|
||||
run: bun build:ratingleaderboard --region=asia
|
||||
@@ -25,4 +25,17 @@ jobs:
|
||||
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
||||
PUBLIC_ASSET_FAST_USER: ${{ secrets.PUBLIC_ASSET_FAST_USER }}
|
||||
PUBLIC_ASSET_FAST_REPO: ${{ secrets.PUBLIC_ASSET_FAST_REPO }}
|
||||
PUBLIC_PROMOTE_OPENTEST: ${{ secrets.PUBLIC_PROMOTE_OPENTEST }}
|
||||
ALLOW_ROBOTS: 'true'
|
||||
WOTB_GLOSSARY: ${{ secrets.WOTB_GLOSSARY }}
|
||||
PUBLIC_GOOGLE_TAG_MANAGER_ID: ${{ secrets.PUBLIC_GOOGLE_TAG_MANAGER_ID }}
|
||||
PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ${{ secrets.PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID }}
|
||||
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
|
||||
WOTB_GLOSSARY_DOMAIN: ${{ secrets.WOTB_GLOSSARY_DOMAIN }}
|
||||
WOTB_GLOSSARY_PATH: ${{ secrets.WOTB_GLOSSARY_PATH }}
|
||||
PUBLIC_DISCORD_SERVER_ID: ${{ secrets.PUBLIC_DISCORD_SERVER_ID }}
|
||||
PUBLIC_ASSET_BASE: ${{ secrets.PUBLIC_ASSET_BASE }}
|
||||
PUBLIC_BRANCH: ${{ secrets.PUBLIC_BRANCH }}
|
||||
run: bun build:ratingleaderboard --region=eu
|
||||
@@ -25,4 +25,17 @@ jobs:
|
||||
DISCORD_TOKEN: ${{ secrets.DISCORD_TOKEN }}
|
||||
DATABASE_URL: ${{ secrets.DATABASE_URL }}
|
||||
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
||||
PUBLIC_ASSET_FAST_USER: ${{ secrets.PUBLIC_ASSET_FAST_USER }}
|
||||
PUBLIC_ASSET_FAST_REPO: ${{ secrets.PUBLIC_ASSET_FAST_REPO }}
|
||||
PUBLIC_PROMOTE_OPENTEST: ${{ secrets.PUBLIC_PROMOTE_OPENTEST }}
|
||||
ALLOW_ROBOTS: 'true'
|
||||
WOTB_GLOSSARY: ${{ secrets.WOTB_GLOSSARY }}
|
||||
PUBLIC_GOOGLE_TAG_MANAGER_ID: ${{ secrets.PUBLIC_GOOGLE_TAG_MANAGER_ID }}
|
||||
PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ${{ secrets.PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID }}
|
||||
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
|
||||
WOTB_GLOSSARY_DOMAIN: ${{ secrets.WOTB_GLOSSARY_DOMAIN }}
|
||||
WOTB_GLOSSARY_PATH: ${{ secrets.WOTB_GLOSSARY_PATH }}
|
||||
PUBLIC_DISCORD_SERVER_ID: ${{ secrets.PUBLIC_DISCORD_SERVER_ID }}
|
||||
PUBLIC_ASSET_BASE: ${{ secrets.PUBLIC_ASSET_BASE }}
|
||||
PUBLIC_BRANCH: ${{ secrets.PUBLIC_BRANCH }}
|
||||
run: bun build:ratingleaderboard --region=com
|
||||
@@ -18,14 +18,19 @@ concurrency:
|
||||
|
||||
env:
|
||||
PUBLIC_WARGAMING_APPLICATION_ID: ${{ secrets.PUBLIC_WARGAMING_APPLICATION_ID }}
|
||||
PUBLIC_ASSET_REPO: ${{ secrets.PUBLIC_ASSET_REPO }}
|
||||
PUBLIC_ASSET_BRANCH: ${{ secrets.PUBLIC_ASSET_BRANCH }}
|
||||
PUBLIC_PROMOTE_OPENTEST: ${{ secrets.PUBLIC_PROMOTE_OPENTEST }}
|
||||
ALLOW_ROBOTS: true
|
||||
ALLOW_ROBOTS: ${{ secrets.ALLOW_ROBOTS }}
|
||||
WOTB_GLOSSARY: ${{ secrets.WOTB_GLOSSARY }}
|
||||
PUBLIC_GOOGLE_TAG_MANAGER_ID: ${{ secrets.PUBLIC_GOOGLE_TAG_MANAGER_ID }}
|
||||
PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID: ${{ secrets.PUBLIC_GOOGLE_ANALYTICS_PROPERTY_ID }}
|
||||
GOOGLE_APPLICATION_CREDENTIALS: ${{ secrets.GOOGLE_APPLICATION_CREDENTIALS }}
|
||||
WOTB_GLOSSARY_DOMAIN: ${{ secrets.WOTB_GLOSSARY_DOMAIN }}
|
||||
WOTB_GLOSSARY_PATH: ${{ secrets.WOTB_GLOSSARY_PATH }}
|
||||
PUBLIC_DISCORD_SERVER_ID: ${{ secrets.PUBLIC_DISCORD_SERVER_ID }}
|
||||
PUBLIC_ASSET_BASE: ${{ secrets.PUBLIC_ASSET_BASE }}
|
||||
PUBLIC_BRANCH: ${{ secrets.PUBLIC_BRANCH }}
|
||||
PUBLIC_GUIDE_WEBSITE: ${{ secrets.PUBLIC_GUIDE_WEBSITE }}
|
||||
SERVICING: ${{ secrets.SERVICING }}
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -52,8 +57,7 @@ jobs:
|
||||
path: dist/website
|
||||
|
||||
deploy-github-pages:
|
||||
if: github.ref == 'refs/heads/main'
|
||||
|
||||
if: ${{ github.ref == 'refs/heads/main' }}
|
||||
name: Deploy to GitHub Pages
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
@@ -65,27 +69,3 @@ jobs:
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v4
|
||||
|
||||
deploy-vercel:
|
||||
name: Deploy to Vercel
|
||||
needs: build
|
||||
runs-on: ubuntu-latest
|
||||
environment:
|
||||
name: Preview
|
||||
|
||||
steps:
|
||||
# vercel begs for the .git dir so here it is my guy
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Download artifact
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: ./dist/website
|
||||
|
||||
- uses: amondnet/vercel-action@v25
|
||||
with:
|
||||
vercel-token: ${{ secrets.VERCEL_TOKEN }}
|
||||
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
vercel-org-id: ${{ secrets.VERCEL_ORG_ID}}
|
||||
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
|
||||
working-directory: ./dist/website
|
||||
+5
-4
@@ -1,14 +1,14 @@
|
||||
node_modules
|
||||
_node_modules
|
||||
package-lock.json
|
||||
.env
|
||||
*.env
|
||||
/test-results/
|
||||
/playwright-report/
|
||||
/playwright/.cache/
|
||||
dist/
|
||||
dist.*
|
||||
yarn-error.log
|
||||
/test.*
|
||||
test.*
|
||||
/docs/.vitepress/dist
|
||||
/docs/.vitepress/cache
|
||||
servers.csv
|
||||
@@ -22,8 +22,9 @@ depots
|
||||
public/sitemap*
|
||||
/firebase.json
|
||||
target
|
||||
# packages/core/src/protos/*
|
||||
# !packages/core/src/protos/*.proto
|
||||
# packages/core/src/protos/*.ts
|
||||
/.vercel
|
||||
/.astro
|
||||
.vercel
|
||||
/src
|
||||
/packages/bot/src/prisma
|
||||
@@ -1,3 +1,9 @@
|
||||
[submodule "submodules/blitzkit-closed"]
|
||||
path = submodules/blitzkit-closed
|
||||
url = https://github.com/tresabhi/blitzkit-closed
|
||||
[submodule "submodules/CUE4Parse"]
|
||||
path = submodules/CUE4Parse
|
||||
url = https://github.com/FabianFG/CUE4Parse
|
||||
[submodule "submodules/blitzkit-internal"]
|
||||
path = submodules/blitzkit-internal
|
||||
url = https://github.com/blitzkit/internal
|
||||
Vendored
+12
@@ -14,6 +14,7 @@
|
||||
"applypatches",
|
||||
"artefacts",
|
||||
"astrojs",
|
||||
"astrolib",
|
||||
"atgm",
|
||||
"Autoloader",
|
||||
"Autoreloader",
|
||||
@@ -35,6 +36,7 @@
|
||||
"cacheable",
|
||||
"Callouts",
|
||||
"Camo",
|
||||
"Carro",
|
||||
"CCPAOPTOUT",
|
||||
"CDON",
|
||||
"classname",
|
||||
@@ -42,6 +44,7 @@
|
||||
"closedkrieg",
|
||||
"cockroackdb",
|
||||
"Coef",
|
||||
"Combattimento",
|
||||
"cooldown",
|
||||
"corelations",
|
||||
"corsproxy",
|
||||
@@ -53,6 +56,7 @@
|
||||
"dbid",
|
||||
"Ddpf",
|
||||
"Ddsd",
|
||||
"deadrail",
|
||||
"debugflags",
|
||||
"deburr",
|
||||
"decalmask",
|
||||
@@ -82,6 +86,7 @@
|
||||
"gameplay",
|
||||
"glsl",
|
||||
"GLTF",
|
||||
"gtag",
|
||||
"haha",
|
||||
"highp",
|
||||
"iife",
|
||||
@@ -104,6 +109,7 @@
|
||||
"Maddoxkkm",
|
||||
"malum",
|
||||
"mantlets",
|
||||
"mediump",
|
||||
"metallicness",
|
||||
"metalness",
|
||||
"minitelrose",
|
||||
@@ -130,9 +136,12 @@
|
||||
"outdir",
|
||||
"outfile",
|
||||
"ownedtanks",
|
||||
"padder",
|
||||
"partytown",
|
||||
"PIXELFORMAT",
|
||||
"playerachievements",
|
||||
"playerinfo",
|
||||
"playform",
|
||||
"pngjs",
|
||||
"POSITIVEX",
|
||||
"POSITIVEY",
|
||||
@@ -181,6 +190,7 @@
|
||||
"TEXCOORD",
|
||||
"tresabhi",
|
||||
"tungstentip",
|
||||
"Turretless",
|
||||
"TYPELESS",
|
||||
"ubjson",
|
||||
"Unicum",
|
||||
@@ -189,6 +199,7 @@
|
||||
"unpickled",
|
||||
"Unregistering",
|
||||
"unrotate",
|
||||
"unwrapper",
|
||||
"vercel",
|
||||
"vickers",
|
||||
"vitepress",
|
||||
@@ -211,6 +222,7 @@
|
||||
"yolo",
|
||||
"youtuber",
|
||||
"youtubers",
|
||||
"zoomable",
|
||||
"zustand"
|
||||
],
|
||||
"deno.enable": false,
|
||||
|
||||
@@ -1,661 +0,0 @@
|
||||
GNU AFFERO GENERAL PUBLIC LICENSE
|
||||
Version 3, 19 November 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU Affero General Public License is a free, copyleft license for
|
||||
software and other kinds of works, specifically designed to ensure
|
||||
cooperation with the community in the case of network server software.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
our General Public Licenses are intended to guarantee your freedom to
|
||||
share and change all versions of a program--to make sure it remains free
|
||||
software for all its users.
|
||||
|
||||
When we speak of free software, we are referring to freedom, not
|
||||
price. Our General Public Licenses are designed to make sure that you
|
||||
have the freedom to distribute copies of free software (and charge for
|
||||
them if you wish), that you receive source code or can get it if you
|
||||
want it, that you can change the software or use pieces of it in new
|
||||
free programs, and that you know you can do these things.
|
||||
|
||||
Developers that use our General Public Licenses protect your rights
|
||||
with two steps: (1) assert copyright on the software, and (2) offer
|
||||
you this License which gives you legal permission to copy, distribute
|
||||
and/or modify the software.
|
||||
|
||||
A secondary benefit of defending all users' freedom is that
|
||||
improvements made in alternate versions of the program, if they
|
||||
receive widespread use, become available for other developers to
|
||||
incorporate. Many developers of free software are heartened and
|
||||
encouraged by the resulting cooperation. However, in the case of
|
||||
software used on network servers, this result may fail to come about.
|
||||
The GNU General Public License permits making a modified version and
|
||||
letting the public access it on a server without ever releasing its
|
||||
source code to the public.
|
||||
|
||||
The GNU Affero General Public License is designed specifically to
|
||||
ensure that, in such cases, the modified source code becomes available
|
||||
to the community. It requires the operator of a network server to
|
||||
provide the source code of the modified version running there to the
|
||||
users of that server. Therefore, public use of a modified version, on
|
||||
a publicly accessible server, gives the public access to the source
|
||||
code of the modified version.
|
||||
|
||||
An older license, called the Affero General Public License and
|
||||
published by Affero, was designed to accomplish similar goals. This is
|
||||
a different license, not a version of the Affero GPL, but Affero has
|
||||
released a new version of the Affero GPL which permits relicensing under
|
||||
this license.
|
||||
|
||||
The precise terms and conditions for copying, distribution and
|
||||
modification follow.
|
||||
|
||||
TERMS AND CONDITIONS
|
||||
|
||||
0. Definitions.
|
||||
|
||||
"This License" refers to version 3 of the GNU Affero General Public License.
|
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
||||
works, such as semiconductor masks.
|
||||
|
||||
"The Program" refers to any copyrightable work licensed under this
|
||||
License. Each licensee is addressed as "you". "Licensees" and
|
||||
"recipients" may be individuals or organizations.
|
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work
|
||||
in a fashion requiring copyright permission, other than the making of an
|
||||
exact copy. The resulting work is called a "modified version" of the
|
||||
earlier work or a work "based on" the earlier work.
|
||||
|
||||
A "covered work" means either the unmodified Program or a work based
|
||||
on the Program.
|
||||
|
||||
To "propagate" a work means to do anything with it that, without
|
||||
permission, would make you directly or secondarily liable for
|
||||
infringement under applicable copyright law, except executing it on a
|
||||
computer or modifying a private copy. Propagation includes copying,
|
||||
distribution (with or without modification), making available to the
|
||||
public, and in some countries other activities as well.
|
||||
|
||||
To "convey" a work means any kind of propagation that enables other
|
||||
parties to make or receive copies. Mere interaction with a user through
|
||||
a computer network, with no transfer of a copy, is not conveying.
|
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices"
|
||||
to the extent that it includes a convenient and prominently visible
|
||||
feature that (1) displays an appropriate copyright notice, and (2)
|
||||
tells the user that there is no warranty for the work (except to the
|
||||
extent that warranties are provided), that licensees may convey the
|
||||
work under this License, and how to view a copy of this License. If
|
||||
the interface presents a list of user commands or options, such as a
|
||||
menu, a prominent item in the list meets this criterion.
|
||||
|
||||
1. Source Code.
|
||||
|
||||
The "source code" for a work means the preferred form of the work
|
||||
for making modifications to it. "Object code" means any non-source
|
||||
form of a work.
|
||||
|
||||
A "Standard Interface" means an interface that either is an official
|
||||
standard defined by a recognized standards body, or, in the case of
|
||||
interfaces specified for a particular programming language, one that
|
||||
is widely used among developers working in that language.
|
||||
|
||||
The "System Libraries" of an executable work include anything, other
|
||||
than the work as a whole, that (a) is included in the normal form of
|
||||
packaging a Major Component, but which is not part of that Major
|
||||
Component, and (b) serves only to enable use of the work with that
|
||||
Major Component, or to implement a Standard Interface for which an
|
||||
implementation is available to the public in source code form. A
|
||||
"Major Component", in this context, means a major essential component
|
||||
(kernel, window system, and so on) of the specific operating system
|
||||
(if any) on which the executable work runs, or a compiler used to
|
||||
produce the work, or an object code interpreter used to run it.
|
||||
|
||||
The "Corresponding Source" for a work in object code form means all
|
||||
the source code needed to generate, install, and (for an executable
|
||||
work) run the object code and to modify the work, including scripts to
|
||||
control those activities. However, it does not include the work's
|
||||
System Libraries, or general-purpose tools or generally available free
|
||||
programs which are used unmodified in performing those activities but
|
||||
which are not part of the work. For example, Corresponding Source
|
||||
includes interface definition files associated with source files for
|
||||
the work, and the source code for shared libraries and dynamically
|
||||
linked subprograms that the work is specifically designed to require,
|
||||
such as by intimate data communication or control flow between those
|
||||
subprograms and other parts of the work.
|
||||
|
||||
The Corresponding Source need not include anything that users
|
||||
can regenerate automatically from other parts of the Corresponding
|
||||
Source.
|
||||
|
||||
The Corresponding Source for a work in source code form is that
|
||||
same work.
|
||||
|
||||
2. Basic Permissions.
|
||||
|
||||
All rights granted under this License are granted for the term of
|
||||
copyright on the Program, and are irrevocable provided the stated
|
||||
conditions are met. This License explicitly affirms your unlimited
|
||||
permission to run the unmodified Program. The output from running a
|
||||
covered work is covered by this License only if the output, given its
|
||||
content, constitutes a covered work. This License acknowledges your
|
||||
rights of fair use or other equivalent, as provided by copyright law.
|
||||
|
||||
You may make, run and propagate covered works that you do not
|
||||
convey, without conditions so long as your license otherwise remains
|
||||
in force. You may convey covered works to others for the sole purpose
|
||||
of having them make modifications exclusively for you, or provide you
|
||||
with facilities for running those works, provided that you comply with
|
||||
the terms of this License in conveying all material for which you do
|
||||
not control copyright. Those thus making or running the covered works
|
||||
for you must do so exclusively on your behalf, under your direction
|
||||
and control, on terms that prohibit them from making any copies of
|
||||
your copyrighted material outside their relationship with you.
|
||||
|
||||
Conveying under any other circumstances is permitted solely under
|
||||
the conditions stated below. Sublicensing is not allowed; section 10
|
||||
makes it unnecessary.
|
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
||||
|
||||
No covered work shall be deemed part of an effective technological
|
||||
measure under any applicable law fulfilling obligations under article
|
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
||||
similar laws prohibiting or restricting circumvention of such
|
||||
measures.
|
||||
|
||||
When you convey a covered work, you waive any legal power to forbid
|
||||
circumvention of technological measures to the extent such circumvention
|
||||
is effected by exercising rights under this License with respect to
|
||||
the covered work, and you disclaim any intention to limit operation or
|
||||
modification of the work as a means of enforcing, against the work's
|
||||
users, your or third parties' legal rights to forbid circumvention of
|
||||
technological measures.
|
||||
|
||||
4. Conveying Verbatim Copies.
|
||||
|
||||
You may convey verbatim copies of the Program's source code as you
|
||||
receive it, in any medium, provided that you conspicuously and
|
||||
appropriately publish on each copy an appropriate copyright notice;
|
||||
keep intact all notices stating that this License and any
|
||||
non-permissive terms added in accord with section 7 apply to the code;
|
||||
keep intact all notices of the absence of any warranty; and give all
|
||||
recipients a copy of this License along with the Program.
|
||||
|
||||
You may charge any price or no price for each copy that you convey,
|
||||
and you may offer support or warranty protection for a fee.
|
||||
|
||||
5. Conveying Modified Source Versions.
|
||||
|
||||
You may convey a work based on the Program, or the modifications to
|
||||
produce it from the Program, in the form of source code under the
|
||||
terms of section 4, provided that you also meet all of these conditions:
|
||||
|
||||
a) The work must carry prominent notices stating that you modified
|
||||
it, and giving a relevant date.
|
||||
|
||||
b) The work must carry prominent notices stating that it is
|
||||
released under this License and any conditions added under section
|
||||
7. This requirement modifies the requirement in section 4 to
|
||||
"keep intact all notices".
|
||||
|
||||
c) You must license the entire work, as a whole, under this
|
||||
License to anyone who comes into possession of a copy. This
|
||||
License will therefore apply, along with any applicable section 7
|
||||
additional terms, to the whole of the work, and all its parts,
|
||||
regardless of how they are packaged. This License gives no
|
||||
permission to license the work in any other way, but it does not
|
||||
invalidate such permission if you have separately received it.
|
||||
|
||||
d) If the work has interactive user interfaces, each must display
|
||||
Appropriate Legal Notices; however, if the Program has interactive
|
||||
interfaces that do not display Appropriate Legal Notices, your
|
||||
work need not make them do so.
|
||||
|
||||
A compilation of a covered work with other separate and independent
|
||||
works, which are not by their nature extensions of the covered work,
|
||||
and which are not combined with it such as to form a larger program,
|
||||
in or on a volume of a storage or distribution medium, is called an
|
||||
"aggregate" if the compilation and its resulting copyright are not
|
||||
used to limit the access or legal rights of the compilation's users
|
||||
beyond what the individual works permit. Inclusion of a covered work
|
||||
in an aggregate does not cause this License to apply to the other
|
||||
parts of the aggregate.
|
||||
|
||||
6. Conveying Non-Source Forms.
|
||||
|
||||
You may convey a covered work in object code form under the terms
|
||||
of sections 4 and 5, provided that you also convey the
|
||||
machine-readable Corresponding Source under the terms of this License,
|
||||
in one of these ways:
|
||||
|
||||
a) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by the
|
||||
Corresponding Source fixed on a durable physical medium
|
||||
customarily used for software interchange.
|
||||
|
||||
b) Convey the object code in, or embodied in, a physical product
|
||||
(including a physical distribution medium), accompanied by a
|
||||
written offer, valid for at least three years and valid for as
|
||||
long as you offer spare parts or customer support for that product
|
||||
model, to give anyone who possesses the object code either (1) a
|
||||
copy of the Corresponding Source for all the software in the
|
||||
product that is covered by this License, on a durable physical
|
||||
medium customarily used for software interchange, for a price no
|
||||
more than your reasonable cost of physically performing this
|
||||
conveying of source, or (2) access to copy the
|
||||
Corresponding Source from a network server at no charge.
|
||||
|
||||
c) Convey individual copies of the object code with a copy of the
|
||||
written offer to provide the Corresponding Source. This
|
||||
alternative is allowed only occasionally and noncommercially, and
|
||||
only if you received the object code with such an offer, in accord
|
||||
with subsection 6b.
|
||||
|
||||
d) Convey the object code by offering access from a designated
|
||||
place (gratis or for a charge), and offer equivalent access to the
|
||||
Corresponding Source in the same way through the same place at no
|
||||
further charge. You need not require recipients to copy the
|
||||
Corresponding Source along with the object code. If the place to
|
||||
copy the object code is a network server, the Corresponding Source
|
||||
may be on a different server (operated by you or a third party)
|
||||
that supports equivalent copying facilities, provided you maintain
|
||||
clear directions next to the object code saying where to find the
|
||||
Corresponding Source. Regardless of what server hosts the
|
||||
Corresponding Source, you remain obligated to ensure that it is
|
||||
available for as long as needed to satisfy these requirements.
|
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided
|
||||
you inform other peers where the object code and Corresponding
|
||||
Source of the work are being offered to the general public at no
|
||||
charge under subsection 6d.
|
||||
|
||||
A separable portion of the object code, whose source code is excluded
|
||||
from the Corresponding Source as a System Library, need not be
|
||||
included in conveying the object code work.
|
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any
|
||||
tangible personal property which is normally used for personal, family,
|
||||
or household purposes, or (2) anything designed or sold for incorporation
|
||||
into a dwelling. In determining whether a product is a consumer product,
|
||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
||||
product received by a particular user, "normally used" refers to a
|
||||
typical or common use of that class of product, regardless of the status
|
||||
of the particular user or of the way in which the particular user
|
||||
actually uses, or expects or is expected to use, the product. A product
|
||||
is a consumer product regardless of whether the product has substantial
|
||||
commercial, industrial or non-consumer uses, unless such uses represent
|
||||
the only significant mode of use of the product.
|
||||
|
||||
"Installation Information" for a User Product means any methods,
|
||||
procedures, authorization keys, or other information required to install
|
||||
and execute modified versions of a covered work in that User Product from
|
||||
a modified version of its Corresponding Source. The information must
|
||||
suffice to ensure that the continued functioning of the modified object
|
||||
code is in no case prevented or interfered with solely because
|
||||
modification has been made.
|
||||
|
||||
If you convey an object code work under this section in, or with, or
|
||||
specifically for use in, a User Product, and the conveying occurs as
|
||||
part of a transaction in which the right of possession and use of the
|
||||
User Product is transferred to the recipient in perpetuity or for a
|
||||
fixed term (regardless of how the transaction is characterized), the
|
||||
Corresponding Source conveyed under this section must be accompanied
|
||||
by the Installation Information. But this requirement does not apply
|
||||
if neither you nor any third party retains the ability to install
|
||||
modified object code on the User Product (for example, the work has
|
||||
been installed in ROM).
|
||||
|
||||
The requirement to provide Installation Information does not include a
|
||||
requirement to continue to provide support service, warranty, or updates
|
||||
for a work that has been modified or installed by the recipient, or for
|
||||
the User Product in which it has been modified or installed. Access to a
|
||||
network may be denied when the modification itself materially and
|
||||
adversely affects the operation of the network or violates the rules and
|
||||
protocols for communication across the network.
|
||||
|
||||
Corresponding Source conveyed, and Installation Information provided,
|
||||
in accord with this section must be in a format that is publicly
|
||||
documented (and with an implementation available to the public in
|
||||
source code form), and must require no special password or key for
|
||||
unpacking, reading or copying.
|
||||
|
||||
7. Additional Terms.
|
||||
|
||||
"Additional permissions" are terms that supplement the terms of this
|
||||
License by making exceptions from one or more of its conditions.
|
||||
Additional permissions that are applicable to the entire Program shall
|
||||
be treated as though they were included in this License, to the extent
|
||||
that they are valid under applicable law. If additional permissions
|
||||
apply only to part of the Program, that part may be used separately
|
||||
under those permissions, but the entire Program remains governed by
|
||||
this License without regard to the additional permissions.
|
||||
|
||||
When you convey a copy of a covered work, you may at your option
|
||||
remove any additional permissions from that copy, or from any part of
|
||||
it. (Additional permissions may be written to require their own
|
||||
removal in certain cases when you modify the work.) You may place
|
||||
additional permissions on material, added by you to a covered work,
|
||||
for which you have or can give appropriate copyright permission.
|
||||
|
||||
Notwithstanding any other provision of this License, for material you
|
||||
add to a covered work, you may (if authorized by the copyright holders of
|
||||
that material) supplement the terms of this License with terms:
|
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the
|
||||
terms of sections 15 and 16 of this License; or
|
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or
|
||||
author attributions in that material or in the Appropriate Legal
|
||||
Notices displayed by works containing it; or
|
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or
|
||||
requiring that modified versions of such material be marked in
|
||||
reasonable ways as different from the original version; or
|
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or
|
||||
authors of the material; or
|
||||
|
||||
e) Declining to grant rights under trademark law for use of some
|
||||
trade names, trademarks, or service marks; or
|
||||
|
||||
f) Requiring indemnification of licensors and authors of that
|
||||
material by anyone who conveys the material (or modified versions of
|
||||
it) with contractual assumptions of liability to the recipient, for
|
||||
any liability that these contractual assumptions directly impose on
|
||||
those licensors and authors.
|
||||
|
||||
All other non-permissive additional terms are considered "further
|
||||
restrictions" within the meaning of section 10. If the Program as you
|
||||
received it, or any part of it, contains a notice stating that it is
|
||||
governed by this License along with a term that is a further
|
||||
restriction, you may remove that term. If a license document contains
|
||||
a further restriction but permits relicensing or conveying under this
|
||||
License, you may add to a covered work material governed by the terms
|
||||
of that license document, provided that the further restriction does
|
||||
not survive such relicensing or conveying.
|
||||
|
||||
If you add terms to a covered work in accord with this section, you
|
||||
must place, in the relevant source files, a statement of the
|
||||
additional terms that apply to those files, or a notice indicating
|
||||
where to find the applicable terms.
|
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the
|
||||
form of a separately written license, or stated as exceptions;
|
||||
the above requirements apply either way.
|
||||
|
||||
8. Termination.
|
||||
|
||||
You may not propagate or modify a covered work except as expressly
|
||||
provided under this License. Any attempt otherwise to propagate or
|
||||
modify it is void, and will automatically terminate your rights under
|
||||
this License (including any patent licenses granted under the third
|
||||
paragraph of section 11).
|
||||
|
||||
However, if you cease all violation of this License, then your
|
||||
license from a particular copyright holder is reinstated (a)
|
||||
provisionally, unless and until the copyright holder explicitly and
|
||||
finally terminates your license, and (b) permanently, if the copyright
|
||||
holder fails to notify you of the violation by some reasonable means
|
||||
prior to 60 days after the cessation.
|
||||
|
||||
Moreover, your license from a particular copyright holder is
|
||||
reinstated permanently if the copyright holder notifies you of the
|
||||
violation by some reasonable means, this is the first time you have
|
||||
received notice of violation of this License (for any work) from that
|
||||
copyright holder, and you cure the violation prior to 30 days after
|
||||
your receipt of the notice.
|
||||
|
||||
Termination of your rights under this section does not terminate the
|
||||
licenses of parties who have received copies or rights from you under
|
||||
this License. If your rights have been terminated and not permanently
|
||||
reinstated, you do not qualify to receive new licenses for the same
|
||||
material under section 10.
|
||||
|
||||
9. Acceptance Not Required for Having Copies.
|
||||
|
||||
You are not required to accept this License in order to receive or
|
||||
run a copy of the Program. Ancillary propagation of a covered work
|
||||
occurring solely as a consequence of using peer-to-peer transmission
|
||||
to receive a copy likewise does not require acceptance. However,
|
||||
nothing other than this License grants you permission to propagate or
|
||||
modify any covered work. These actions infringe copyright if you do
|
||||
not accept this License. Therefore, by modifying or propagating a
|
||||
covered work, you indicate your acceptance of this License to do so.
|
||||
|
||||
10. Automatic Licensing of Downstream Recipients.
|
||||
|
||||
Each time you convey a covered work, the recipient automatically
|
||||
receives a license from the original licensors, to run, modify and
|
||||
propagate that work, subject to this License. You are not responsible
|
||||
for enforcing compliance by third parties with this License.
|
||||
|
||||
An "entity transaction" is a transaction transferring control of an
|
||||
organization, or substantially all assets of one, or subdividing an
|
||||
organization, or merging organizations. If propagation of a covered
|
||||
work results from an entity transaction, each party to that
|
||||
transaction who receives a copy of the work also receives whatever
|
||||
licenses to the work the party's predecessor in interest had or could
|
||||
give under the previous paragraph, plus a right to possession of the
|
||||
Corresponding Source of the work from the predecessor in interest, if
|
||||
the predecessor has it or can get it with reasonable efforts.
|
||||
|
||||
You may not impose any further restrictions on the exercise of the
|
||||
rights granted or affirmed under this License. For example, you may
|
||||
not impose a license fee, royalty, or other charge for exercise of
|
||||
rights granted under this License, and you may not initiate litigation
|
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
||||
any patent claim is infringed by making, using, selling, offering for
|
||||
sale, or importing the Program or any portion of it.
|
||||
|
||||
11. Patents.
|
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this
|
||||
License of the Program or a work on which the Program is based. The
|
||||
work thus licensed is called the contributor's "contributor version".
|
||||
|
||||
A contributor's "essential patent claims" are all patent claims
|
||||
owned or controlled by the contributor, whether already acquired or
|
||||
hereafter acquired, that would be infringed by some manner, permitted
|
||||
by this License, of making, using, or selling its contributor version,
|
||||
but do not include claims that would be infringed only as a
|
||||
consequence of further modification of the contributor version. For
|
||||
purposes of this definition, "control" includes the right to grant
|
||||
patent sublicenses in a manner consistent with the requirements of
|
||||
this License.
|
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
||||
patent license under the contributor's essential patent claims, to
|
||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
||||
propagate the contents of its contributor version.
|
||||
|
||||
In the following three paragraphs, a "patent license" is any express
|
||||
agreement or commitment, however denominated, not to enforce a patent
|
||||
(such as an express permission to practice a patent or covenant not to
|
||||
sue for patent infringement). To "grant" such a patent license to a
|
||||
party means to make such an agreement or commitment not to enforce a
|
||||
patent against the party.
|
||||
|
||||
If you convey a covered work, knowingly relying on a patent license,
|
||||
and the Corresponding Source of the work is not available for anyone
|
||||
to copy, free of charge and under the terms of this License, through a
|
||||
publicly available network server or other readily accessible means,
|
||||
then you must either (1) cause the Corresponding Source to be so
|
||||
available, or (2) arrange to deprive yourself of the benefit of the
|
||||
patent license for this particular work, or (3) arrange, in a manner
|
||||
consistent with the requirements of this License, to extend the patent
|
||||
license to downstream recipients. "Knowingly relying" means you have
|
||||
actual knowledge that, but for the patent license, your conveying the
|
||||
covered work in a country, or your recipient's use of the covered work
|
||||
in a country, would infringe one or more identifiable patents in that
|
||||
country that you have reason to believe are valid.
|
||||
|
||||
If, pursuant to or in connection with a single transaction or
|
||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
||||
covered work, and grant a patent license to some of the parties
|
||||
receiving the covered work authorizing them to use, propagate, modify
|
||||
or convey a specific copy of the covered work, then the patent license
|
||||
you grant is automatically extended to all recipients of the covered
|
||||
work and works based on it.
|
||||
|
||||
A patent license is "discriminatory" if it does not include within
|
||||
the scope of its coverage, prohibits the exercise of, or is
|
||||
conditioned on the non-exercise of one or more of the rights that are
|
||||
specifically granted under this License. You may not convey a covered
|
||||
work if you are a party to an arrangement with a third party that is
|
||||
in the business of distributing software, under which you make payment
|
||||
to the third party based on the extent of your activity of conveying
|
||||
the work, and under which the third party grants, to any of the
|
||||
parties who would receive the covered work from you, a discriminatory
|
||||
patent license (a) in connection with copies of the covered work
|
||||
conveyed by you (or copies made from those copies), or (b) primarily
|
||||
for and in connection with specific products or compilations that
|
||||
contain the covered work, unless you entered into that arrangement,
|
||||
or that patent license was granted, prior to 28 March 2007.
|
||||
|
||||
Nothing in this License shall be construed as excluding or limiting
|
||||
any implied license or other defenses to infringement that may
|
||||
otherwise be available to you under applicable patent law.
|
||||
|
||||
12. No Surrender of Others' Freedom.
|
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or
|
||||
otherwise) that contradict the conditions of this License, they do not
|
||||
excuse you from the conditions of this License. If you cannot convey a
|
||||
covered work so as to satisfy simultaneously your obligations under this
|
||||
License and any other pertinent obligations, then as a consequence you may
|
||||
not convey it at all. For example, if you agree to terms that obligate you
|
||||
to collect a royalty for further conveying from those to whom you convey
|
||||
the Program, the only way you could satisfy both those terms and this
|
||||
License would be to refrain entirely from conveying the Program.
|
||||
|
||||
13. Remote Network Interaction; Use with the GNU General Public License.
|
||||
|
||||
Notwithstanding any other provision of this License, if you modify the
|
||||
Program, your modified version must prominently offer all users
|
||||
interacting with it remotely through a computer network (if your version
|
||||
supports such interaction) an opportunity to receive the Corresponding
|
||||
Source of your version by providing access to the Corresponding Source
|
||||
from a network server at no charge, through some standard or customary
|
||||
means of facilitating copying of software. This Corresponding Source
|
||||
shall include the Corresponding Source for any work covered by version 3
|
||||
of the GNU General Public License that is incorporated pursuant to the
|
||||
following paragraph.
|
||||
|
||||
Notwithstanding any other provision of this License, you have
|
||||
permission to link or combine any covered work with a work licensed
|
||||
under version 3 of the GNU General Public License into a single
|
||||
combined work, and to convey the resulting work. The terms of this
|
||||
License will continue to apply to the part which is the covered work,
|
||||
but the work with which it is combined will remain governed by version
|
||||
3 of the GNU General Public License.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU Affero General Public License from time to time. Such new versions
|
||||
will be similar in spirit to the present version, but may differ in detail to
|
||||
address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Program specifies that a certain numbered version of the GNU Affero General
|
||||
Public License "or any later version" applies to it, you have the
|
||||
option of following the terms and conditions either of that numbered
|
||||
version or of any later version published by the Free Software
|
||||
Foundation. If the Program does not specify a version number of the
|
||||
GNU Affero General Public License, you may choose any version ever published
|
||||
by the Free Software Foundation.
|
||||
|
||||
If the Program specifies that a proxy can decide which future
|
||||
versions of the GNU Affero General Public License can be used, that proxy's
|
||||
public statement of acceptance of a version permanently authorizes you
|
||||
to choose that version for the Program.
|
||||
|
||||
Later license versions may give you additional or different
|
||||
permissions. However, no additional obligations are imposed on any
|
||||
author or copyright holder as a result of your choosing to follow a
|
||||
later version.
|
||||
|
||||
15. Disclaimer of Warranty.
|
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
||||
|
||||
16. Limitation of Liability.
|
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGES.
|
||||
|
||||
17. Interpretation of Sections 15 and 16.
|
||||
|
||||
If the disclaimer of warranty and limitation of liability provided
|
||||
above cannot be given local legal effect according to their terms,
|
||||
reviewing courts shall apply local law that most closely approximates
|
||||
an absolute waiver of all civil liability in connection with the
|
||||
Program, unless a warranty or assumption of liability accompanies a
|
||||
copy of the Program in return for a fee.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
How to Apply These Terms to Your New Programs
|
||||
|
||||
If you develop a new program, and you want it to be of the greatest
|
||||
possible use to the public, the best way to achieve this is to make it
|
||||
free software which everyone can redistribute and change under these terms.
|
||||
|
||||
To do so, attach the following notices to the program. It is safest
|
||||
to attach them to the start of each source file to most effectively
|
||||
state the exclusion of warranty; and each file should have at least
|
||||
the "copyright" line and a pointer to where the full notice is found.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If your software can interact with users remotely through a computer
|
||||
network, you should also make sure that it provides a way for users to
|
||||
get its source. For example, if your program is a web application, its
|
||||
interface could display a "Source" link that leads users to an archive
|
||||
of the code. There are many ways you could offer source, and different
|
||||
solutions will be better for different programs; see section 13 for the
|
||||
specific requirements.
|
||||
|
||||
You should also get your employer (if you work as a programmer) or school,
|
||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
||||
For more information on this, and how to apply and follow the GNU AGPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
# BlitzKit License
|
||||
|
||||
Version 1.1, August 5th, 2025. Copyright (c) TrèsAbhi.
|
||||
|
||||
Permission is hereby granted to anyone to:
|
||||
|
||||
- Fork, clone, and download the contents of this repository.
|
||||
- Modify the code locally in private.
|
||||
- Use and run the code **only for personal, non-public testing, or educational purposes**.
|
||||
|
||||
The following restrictions apply:
|
||||
|
||||
- You may **not** deploy, host, or make this project or any derivative publicly accessible.
|
||||
- You may **not** share screenshots, recordings, or any form of media from this project unless you intend to merge your changes back into BlitzKit.
|
||||
- You may **not** use this project or its contents in any public or commercial product.
|
||||
- You may **not** redistribute modified or unmodified versions of this project.
|
||||
|
||||
Contributions:
|
||||
|
||||
- You are encouraged to propose changes or improvements via pull requests to the original BlitzKit repository.
|
||||
- Any such contributions will be considered under the same license terms unless explicitly stated otherwise.
|
||||
|
||||
Violations of this license may result in revocation of usage rights and takedown requests.
|
||||
|
||||
For questions or licensing inquiries, contact support@blitzkit.app.
|
||||
|
||||
## Notes on Existing Forks
|
||||
|
||||
All forks fall under these categories:
|
||||
|
||||
- If your fork was made from commit `8462901` (Apr 17, 2023) or between commits `2958124` (Jul 3, 2023) and `85e483e` (Jul 13, 2024), your fork falls under the **MIT license**.
|
||||
- If your fork was made from commits between `5646093` (Jul 13, 2024) and `e3f131c` (Aug 5, 2025), your fork falls under the **AGPL-3.0 license**.
|
||||
- If your fork was made between commit `f7c356d` (Apr 17, 2023) and `2958124` (Jul 3, 2023), your fork falls under **a default exclusive copyright**.
|
||||
- If your fork was made from commits between `e3f131c` (Aug 5, 2025) and today, your fork falls under **this license**.
|
||||
|
||||
MIT and AGPL-3.0 licensed fork owners:
|
||||
|
||||
- You may continue to use your fork of BlitzKit under the corresponding license.
|
||||
- You may upgrade your fork up to commit `5cab394` (Aug 4, 2025) and keep the AGPL-3.0 license.
|
||||
- You may upgrade to commit `e3f131c` (Aug 5, 2025) or beyond but have to **switch to this license** where all rules apply.
|
||||
- If you upgrade to commit `e3f131c` (Aug 5, 2025) or beyond, you must retract all public deployments of BlitzKit.
|
||||
- Existing screenshots, recordings, or any form of media can remain.
|
||||
|
||||
Default exclusive copyright fork owners:
|
||||
|
||||
- You may continue to use their forks under the AGPL-3.0 license as no license was applied to BlitzKit at the time of forking.
|
||||
|
||||
BlitzKit licensed fork owners:
|
||||
|
||||
- You may continue to upgrade to the latest commits only under the conditions of this license.
|
||||
@@ -1,23 +1,13 @@
|
||||
## Visit the website
|
||||
## BlitzKit
|
||||
|
||||
Your premier source for all things Blitz.
|
||||
|
||||
### https://blitzkit.app/
|
||||
|
||||

|
||||
|
||||
# BlitzKit
|
||||
|
||||
[](https://codeium.com)
|
||||
|
||||
Tools for everything World of Tanks Blitz
|
||||

|
||||
|
||||
## Invite the bot
|
||||
|
||||
Go to [application directory for BlitzKit](https://discord.com/application-directory/1097673957865443370) and click "Add to Server." Voila! You're ready to go.
|
||||
|
||||

|
||||
|
||||
## Visit the documentation website
|
||||
|
||||
### https://tresabhi.github.io/blitzkit/
|
||||
|
||||

|
||||
+1
-1
@@ -1,3 +1,3 @@
|
||||
files:
|
||||
- source: /packages/core/lang/en-US.json
|
||||
- source: /packages/i18n/strings/en.json
|
||||
translation: /%original_path%/%locale%.json
|
||||
@@ -5,6 +5,7 @@ BlitzKit is a one man band **TrèsAbhi** but I am far from solo.
|
||||
| Role | People |
|
||||
| ------------------------------ | ------------------------------ |
|
||||
| Bot verification | S0AP |
|
||||
| General testing | Prince_NA |
|
||||
| Bot advertisement platform | S0AP |
|
||||
| Bot rendering pipeline | Vovko |
|
||||
| Game asset decompression | Maddox |
|
||||
@@ -12,7 +13,7 @@ BlitzKit is a one man band **TrèsAbhi** but I am far from solo.
|
||||
| Game file layout | Aeson |
|
||||
| 3-caliber rule edge cases | Minitelrose, ChickenMan7777 |
|
||||
| Embed UX | \_34, HisRoyalFatness, Synx |
|
||||
| Tankopedia pre-release testing | [OPTML], Aeson, \_34 |
|
||||
| Tankopedia pre-release testing | [OPTML], Aeson, \_34, xkdkw |
|
||||
| Website advertisement platform | Aeson |
|
||||
| Compare pre-release testing | [OPTML] |
|
||||
| Redacted | GonnaHetzMe |
|
||||
@@ -0,0 +1,19 @@
|
||||
# BlitzKit 1.26.5
|
||||
|
||||
¡Ahora en 6 idiomas! This version of BlitzKit adds support for 4 new languages totalling up to 6! [Please help translate on Crowdin](https://crowdin.com/project/blitzkrieg).
|
||||
|
||||
## Features
|
||||
|
||||
- Added Croatian, Russian, Ukrainian, and Chinese
|
||||
- Pre-existing languages: English, Spanish
|
||||
- Added better lighting making tanks a little less yellow and a bit more realistic
|
||||
- Added custom tank icons (some may be missing when the update drops; just give them an hour or so to update)
|
||||
- Increased the maximum recently viewed tanks list size to 14
|
||||
- Tweaked the tank name in the hero section of the Tankopedia to allow the tank to be in the center of the page
|
||||
- The headers in the Performance tool are now sticky just like the Compare tool
|
||||
|
||||
## Fixes
|
||||
|
||||
- Removed unnecessary third party script that did absolutely nothing
|
||||
- Localizations are now stricter in what they allow, reducing errors in the Discord bot
|
||||
- Added 50 gallons of tomato soup to the bot in an attempt to keep it alive
|
||||
@@ -0,0 +1,15 @@
|
||||
# BlitzKit 1.26.6
|
||||
|
||||
This update only affects the website.
|
||||
|
||||
## Features
|
||||
|
||||
- Added an option to hide the tank model beneath the armor
|
||||
|
||||
## Fixes
|
||||
|
||||
- 3RC is now only display when it is used to avoid a ricochet in the advanced armor highlighting mode
|
||||
- Fixed the excessively sharp lighting in static mode
|
||||
- Brightness for non-PBR tanks is a bit better now
|
||||
- Decimal places are now properly rounded in BlitzKit link embeds
|
||||
- The titles in the Tankopedia pages aren't too massive now
|
||||
@@ -0,0 +1,14 @@
|
||||
# BlitzKit 1.27.0
|
||||
|
||||
PLEASE HELP TRANSLATE BLITZKIT: https://crowdin.com/project/blitzkrieg
|
||||
|
||||
This update will be the last major update before the release of World of Tanks Blitz Unreal Engine.
|
||||
|
||||
## Features
|
||||
|
||||
- Added support for English, Spanish, French, Japanese, Polish, Portuguese, Russian, Ukrainian, and Chinese to the website and bot
|
||||
- You can switch languages through the home page, the footer of any page, or the settings page
|
||||
|
||||
## Fixes
|
||||
|
||||
- Fixed the units for shell capacity
|
||||
@@ -0,0 +1,7 @@
|
||||
# BlitzKit 1.27.1
|
||||
|
||||
## Fixes
|
||||
|
||||
- Fixed a crash that occurs if tanks are deleted in Blitz and were once available in BlitzKit
|
||||
- All tank icons are now back
|
||||
- The tank search once again returns results
|
||||
@@ -0,0 +1,23 @@
|
||||
# BlitzKit 1.27.10
|
||||
|
||||
This update changes the URLs across the whole website, removing the "tools" prefix and simplifying other aspects too.
|
||||
|
||||
## Changes
|
||||
|
||||
- Removed "full" tank names
|
||||
- For example, tanks like the "Carro 45t" had full names like "Carro Combattimento 45t" which remained pretty much unused, so they have been removed
|
||||
- Reduced the shadow below the navigation bar
|
||||
- Removed the "tools" prefix from the URLs; here are the paths:
|
||||
- `/tools/tankopedia` -> `/tanks`
|
||||
- `/tools/tankopedia/12345` -> `/tanks/tank-name`
|
||||
- `/tools/compare` -> `/compare`
|
||||
- `/tools/embed` -> `/embed`
|
||||
- `/tools/embed/embed-name` -> `/embed/embed-name`
|
||||
- `/tools/gallery` -> `/gallery`
|
||||
- `/tools/performance` -> `/performance`
|
||||
- `/tools/session` -> `/session`
|
||||
- `/tools/tier-list` -> `/tier-list`
|
||||
|
||||
## Technical Features
|
||||
|
||||
- The asset mangler now uses http headers and even more heuristics to minimize re-creating unchanged assets
|
||||
@@ -0,0 +1,7 @@
|
||||
# BlitzKit 1.27.11
|
||||
|
||||
This update affects both the bot and the website.
|
||||
|
||||
## Technical Changes
|
||||
|
||||
- Added a proper CDN domain to avoid error 429s and any slowdowns
|
||||
@@ -0,0 +1,18 @@
|
||||
# BlitzKit 1.27.12
|
||||
|
||||
This update only affects the website.
|
||||
|
||||
## Features
|
||||
|
||||
- Added the ability to sort by HE shell penetration
|
||||
- The Tankopedia compare bars now account for equipment and selected shells
|
||||
- Made the hero section of the Tankopedia a bit shorter to show users that the page is scrollable
|
||||
|
||||
## Fixes
|
||||
|
||||
- The "Clear filters" button no longer shows up after clearing the search bar
|
||||
- Guns for some tanks no longer go transparent when far away from the camera
|
||||
- The dynamic armor tab no longer lags and flickers when rotating the turret of a tank
|
||||
- Reimplemented the missing tool backgrounds in the navigation bar hamburger menu
|
||||
- The navigation bar now properly goes transparent for pages that request like the Tankopedia pages
|
||||
- Removed the tank name text outline because it doesn't work on most devices
|
||||
@@ -0,0 +1,19 @@
|
||||
# BlitzKit 1.27.13
|
||||
|
||||
This update adds a feature for a future version of WoTB 👁️👃👁️
|
||||
|
||||
## Features
|
||||
|
||||
- Added compatibility for the new mechanic for the upcoming Polish Tank Destroyers
|
||||
- This code will remain dormant until the update for WoTB is released
|
||||
- Added a progress bar to the hero section of the Tankopedia to show that the model is loading
|
||||
- Reordered some Tankopedia statistics to bring important statistics like Damage to the very top
|
||||
|
||||
## Fixes
|
||||
|
||||
- The second column in the footer is now aligned on mobile devices
|
||||
- Fixed an issue that stopped the armor highlighting from working on the Kiwi browser and on older devices
|
||||
|
||||
## Technical Changes
|
||||
|
||||
- Removed permissions for robots to crawl non-blitzkit.app domains
|
||||
@@ -0,0 +1,8 @@
|
||||
# BlitzKit 1.27.14
|
||||
|
||||
This is the 14th patch for `1.27`, making it the new longest lasting version beating the previous record of `1.15.13`!
|
||||
|
||||
## Fixes
|
||||
|
||||
- Optimized the rendering of the shells in the Tankopedia search
|
||||
- The Assault Shells cursor now works on iOS devices
|
||||
@@ -0,0 +1,7 @@
|
||||
# BlitzKit 1.27.15
|
||||
|
||||
I did not see this coming
|
||||
|
||||
## Fixes
|
||||
|
||||
- The Assault Shell graph now supports damage factors of above 100% now
|
||||
@@ -0,0 +1,25 @@
|
||||
# BlitzKit 1.27.16
|
||||
|
||||
## Features
|
||||
|
||||
- Added links to GuidesBlitz to Tankopedia to aid users understand tanks beyond just numbers and stats
|
||||
- Added a gun depression and yaw visualizer
|
||||
|
||||
## Changes
|
||||
|
||||
- Made the colors of the advanced highlighting mode more subtle
|
||||
- Made the Tankopedia stat lines more condensed
|
||||
- You can now scroll the page even with your cursor on the Tankopedia sandbox
|
||||
|
||||
## Fixes
|
||||
|
||||
- Fixed a bug where the range of increased gun depression was incorrectly doubled
|
||||
- Removed an unintended space before the "x" in the "Gun damaged" stat
|
||||
- Fixed an issue causing the 3D renderer to render frames even when off screen
|
||||
- Fixed a differential issue causing excessive rerendering of the stat lines
|
||||
- Images no longer exceed the width of the device in the docs
|
||||
- Assault shells no longer scale the module damage with distance
|
||||
|
||||
## Technical Changes
|
||||
|
||||
- Removed all code relating to the canceled "Shooting Range" mode
|
||||
@@ -0,0 +1,18 @@
|
||||
# BlitzKit 1.27.17
|
||||
|
||||
This update was released early for the website. Today, it'll be officially announced and released for the bot
|
||||
|
||||
## Features
|
||||
|
||||
- Added the shell reload visualizer to aid people in getting a feel for how long shell reloads really are
|
||||
- Added lines of stats for the burst shells
|
||||
|
||||
## Changes
|
||||
|
||||
- Removed the redundant word "Shell" from "Shell reload" and "Shell reloads"
|
||||
- Removed the penetration over distance slider
|
||||
|
||||
## Fixes
|
||||
|
||||
- Fixed the DPM of tanks with burst shells like the ATAC
|
||||
- The DPM will still be different from the game due to a bug in World of Tanks Blitz; I am trying to get Wargaming to fix it; trust BlitzKit!
|
||||
@@ -0,0 +1,7 @@
|
||||
# BlitzKit 1.27.2
|
||||
|
||||
This update only affects the website.
|
||||
|
||||
## Fixes
|
||||
|
||||
- The new Improved Vertical Stabilizer equipment which only affects the gun depression found on the Type 63 now works
|
||||
@@ -0,0 +1,9 @@
|
||||
# BlitzKit 1.27.3
|
||||
|
||||
This update only affects the bot.
|
||||
|
||||
## Fixes
|
||||
|
||||
- Added support for 64-bit IDs allowing users with new accounts to link with BlitzKit
|
||||
- This comes at the added cost of resetting the links of all other accounts
|
||||
- Just re-link and you're good to go
|
||||
@@ -0,0 +1,3 @@
|
||||
# FreakKit 1.27.4
|
||||
|
||||
It has come to our attention that tanks are very harsh objects. To even it out, we made the website a pretty pretty princess <3
|
||||
@@ -0,0 +1,11 @@
|
||||
# BlitzKit 1.27.5
|
||||
|
||||
This update only affects the bot.
|
||||
|
||||
## Changes
|
||||
|
||||
- Removed `/auction`
|
||||
|
||||
## Fixes
|
||||
|
||||
- Fixed a bug that caused `/rating` to disappear
|
||||
@@ -0,0 +1,23 @@
|
||||
# BlitzKit 1.27.6
|
||||
|
||||
This update only affects the website.
|
||||
|
||||
## Features
|
||||
|
||||
- Added a promotional card for [the official Discord server](https://discord.gg/nDt7AjGJQH) to the homepage
|
||||
- Added a better navbar
|
||||
- The added spaces and padding helps add more room for error when clicking, especially on mobile
|
||||
- The dropdown menu is now a lost smaller, disposing of the need to scroll at all
|
||||
- Added shell filters to the tank search
|
||||
- Reworked the filter buttons and their positions to allow for more space
|
||||
|
||||
## Fixes
|
||||
|
||||
- Moved most images from imgur to BlitzKit allowing for users in certain countries to load BlitzKit without getting blocked
|
||||
|
||||
## Technical Features
|
||||
|
||||
- Added Partytown to offload some workload off the main thread, allowing for a more responsive experience
|
||||
- Reworked `robots.txt` to disallow indexing of BlitzKit variants
|
||||
- Improved the SEO further for most pages
|
||||
- Added a few compressor library to speed up load times
|
||||
@@ -0,0 +1,25 @@
|
||||
# BlitzKit 1.27.7
|
||||
|
||||

|
||||
|
||||
This update only affects the website.
|
||||
|
||||
## Features
|
||||
|
||||
- Added a new foggy-wireframe transition between tabs to smooth out the jarring jumps
|
||||
- Added animations pop-in and out animations on a few elements
|
||||
- The tank name title now shrinks in size as soon as a disturbance is caused
|
||||
- The shell selector, antagonist switcher, and thicknesses range now ease into frame
|
||||
- The Tankopedia search page now loads as a skeleton by default before populating with tanks, allowing for the recently viewed tanks to load without cumulative shift
|
||||
- Something similar was done to the Gallery tool
|
||||
- Gave the meta section of the website some zest with nation-based backdrops
|
||||
- The compare tabs in the Tankopedia are now centered
|
||||
|
||||
## Fixes
|
||||
|
||||
- The camera no longer snaps to the initial position when switching between tabs
|
||||
|
||||
## Technical Changes
|
||||
|
||||
- Backported some technologies from BlitzKit Reforged; you will not notice any differences in usage
|
||||
- The popular tanks and gallery indexings have been moved to the asynchronous cron job
|
||||
@@ -0,0 +1,12 @@
|
||||
# BlitzKit 1.27.8
|
||||
|
||||

|
||||
|
||||
## Features
|
||||
|
||||
- The website now uses Inter as the font
|
||||
- Added a cool new non-disturbed state for the Tankopedia because why not
|
||||
|
||||
## Changes
|
||||
|
||||
- Removed the Discord plug and language changer from the homepage
|
||||
@@ -0,0 +1,27 @@
|
||||
# BlitzKit 1.27.9
|
||||
|
||||
BlitzKit's great, but there's far too many numbers. This update adds a few visualizers to help new players understand how things relate numerically.
|
||||
|
||||

|
||||
|
||||
## Features
|
||||
|
||||
- Added the turret and hull traverse speed visualizer
|
||||
- Added the shell ricochet and normalization angles visualizer
|
||||
- Added the view-range visualizer
|
||||
- Added a search bar to the Tankopedia characteristics
|
||||
- Bumped the decimal places for vehicle dimensions and volume
|
||||
- Made tank ranks softer (the bars beneath the tank characteristics)
|
||||
- Gave the navigation bar better distinction from the rest of the page
|
||||
- Increased the number of characteristics rows to 3 on select devices
|
||||
- Switched to a more contrasting classic style of components across the website (it's subtle, but beautiful)
|
||||
|
||||
## Changes
|
||||
|
||||
- Removed units
|
||||
|
||||
## Fixes
|
||||
|
||||
- Clarified a few confusing row labels in the Compare tool
|
||||
- Made the Tankopedia hero section dynamically smaller on mobile phones to allow scrolling
|
||||
- Tank ranks no longer reach 0 or go above the number of vehicles in the comparison
|
||||
+14
-7
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "blitzkit",
|
||||
"private": true,
|
||||
"version": "1.26.4",
|
||||
"version": "1.27.17",
|
||||
"description": "🎉 Tools for everything World of Tanks Blitz",
|
||||
"type": "module",
|
||||
"types": "./types.d.ts",
|
||||
@@ -21,6 +21,7 @@
|
||||
"start:bot": "bun dist/bot/main.js",
|
||||
"dev:docs": "vitepress dev docs",
|
||||
"dev:website": "cd packages/website && bun run dev",
|
||||
"dev": "bun run dev:website",
|
||||
"dev:api": "bun --filter=@blitzkit/api run dev",
|
||||
"setup:depotdownloader": "bun --filter=@blitzkit/scripts run setup:depotdownloader",
|
||||
"setup:patches": "bun --filter=@blitzkit/scripts run setup:patches",
|
||||
@@ -35,18 +36,24 @@
|
||||
"build:protos": "bun packages/scripts/src/protos.ts",
|
||||
"preview:website": "cd packages/website && bun run preview",
|
||||
"build:reviews": "cd packages/scripts && bun build:reviews",
|
||||
"build:ids": "cd packages/scripts && bun build:ids"
|
||||
"build:ids": "cd packages/scripts && bun build:ids",
|
||||
"prunestrings": "cd packages/scripts && bun prunestrings"
|
||||
},
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"lodash-es": "^4.17.21"
|
||||
"cheerio": "^1.1.2",
|
||||
"googleapis": "^144.0.0",
|
||||
"lodash-es": "^4.17.21",
|
||||
"protobufjs": "^7.5.2",
|
||||
"quicklime": "^1.2.0",
|
||||
"sharp": "^0.33.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/bun": "latest",
|
||||
"@types/lodash-es": "^4.17.12",
|
||||
"@types/node": "^22.5.4",
|
||||
"prettier": "^3.3.3",
|
||||
"prisma": "^6.0.0",
|
||||
"typescript": "^5.5.4"
|
||||
"@types/node": "^22.14.1",
|
||||
"prettier": "^3.5.3",
|
||||
"prisma": "^6.6.0",
|
||||
"typescript": "^5.8.3"
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
"types": "src/types.d.ts",
|
||||
"dependencies": {
|
||||
"@blitzkit/core": "workspace:*",
|
||||
"@blitzkit/i18n": "workspace:*",
|
||||
"satori": "^0.10.14",
|
||||
"@resvg/resvg-js": "^2.6.2",
|
||||
"discord.js": "^14.16.3",
|
||||
|
||||
@@ -28,10 +28,10 @@ export const aboutCommand = new Promise<CommandRegistry>(async (resolve) => {
|
||||
|
||||
async handler(interaction) {
|
||||
const subcommand = interaction.options.getSubcommand();
|
||||
const { t } = translator(interaction.locale);
|
||||
const { strings } = translator(interaction.locale);
|
||||
|
||||
if (subcommand === 'commands') {
|
||||
return t`bot.commands.about.subcommands.commands.body${(
|
||||
return `${strings.bot.commands.about.subcommands.commands.body}${(
|
||||
await Promise.all(COMMANDS_RAW)
|
||||
)
|
||||
.sort((a, b) =>
|
||||
|
||||
@@ -3,17 +3,18 @@ import {
|
||||
Region,
|
||||
regionToRegionSubdomain,
|
||||
} from '@blitzkit/core';
|
||||
import { literals } from '@blitzkit/i18n';
|
||||
import { tankDefinitions } from '../core/blitzkit/nonBlockingPromises';
|
||||
import { chunkLines } from '../core/discord/chunkLines';
|
||||
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
||||
import { translator } from '../core/localization/translator';
|
||||
import { CommandRegistry } from '../events/interactionCreate';
|
||||
|
||||
interface Auction {
|
||||
type Auction = null | {
|
||||
count: number;
|
||||
has_next: boolean;
|
||||
results: Result[];
|
||||
}
|
||||
};
|
||||
|
||||
type Result =
|
||||
| {
|
||||
@@ -27,7 +28,7 @@ type Result =
|
||||
available_from?: Date;
|
||||
available_before?: Date;
|
||||
price?: Price;
|
||||
next_price?: Price | null;
|
||||
next_price: Price | null;
|
||||
available: true;
|
||||
display?: boolean;
|
||||
next_price_datetime: Date;
|
||||
@@ -75,7 +76,7 @@ export const auctionCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
command: createLocalizedCommand('auction'),
|
||||
|
||||
async handler(interaction) {
|
||||
const { t, translate } = translator(interaction.locale);
|
||||
const { strings } = translator(interaction.locale);
|
||||
const awaitedTankDefinitions = await tankDefinitions;
|
||||
const region: Region = 'com';
|
||||
const pageSize = 80;
|
||||
@@ -87,16 +88,16 @@ export const auctionCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
pageSize
|
||||
}&type[]=vehicle&saleable=${saleable}`,
|
||||
).then((response) => response.json() as Promise<Auction>);
|
||||
const saleableTanks = data.results.filter((result) => result.available);
|
||||
|
||||
if (saleableTanks.length === 0) {
|
||||
return t`bot.commands.auction.errors.no_auction`;
|
||||
if (data === null) {
|
||||
return strings.bot.commands.auction.errors.no_auction;
|
||||
}
|
||||
|
||||
const saleableTanks = data.results.filter((result) => result.available);
|
||||
const nextPricesTimestamp = saleableTanks[0].next_price_timestamp;
|
||||
|
||||
const title = `# ${t`bot.commands.auction.body.title`}`;
|
||||
const subtitle = `${translate('bot.commands.auction.body.subtitle', [
|
||||
const title = `# ${strings.bot.commands.auction.body.title}`;
|
||||
const subtitle = `${literals(strings.bot.commands.auction.body.subtitle, [
|
||||
`${saleableTanks.length} / ${data.results.length}`,
|
||||
`<t:${nextPricesTimestamp}:R>`,
|
||||
'<https://wotblitz.com/auction/>',
|
||||
@@ -106,19 +107,24 @@ export const auctionCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
|
||||
if (!tank) return '';
|
||||
|
||||
const name = `[${tank.name}](<https://blitzkit.app/tools/tankopedia/${
|
||||
tank.id
|
||||
const name = `[${tank.name}](<https://blitzkit.app/tanks/${
|
||||
tank.slug
|
||||
}>)`;
|
||||
const next = translate('bot.commands.auction.body.next', [
|
||||
`<:gold:1317173197082333244> ${data.next_price!.value.toLocaleString(
|
||||
interaction.locale,
|
||||
)}`,
|
||||
]);
|
||||
const available = translate('bot.commands.auction.body.available', [
|
||||
data.current_count.toLocaleString(interaction.locale),
|
||||
data.initial_count.toLocaleString(interaction.locale),
|
||||
]);
|
||||
const nextLine = `\n-# ${next}`;
|
||||
const next =
|
||||
data.next_price === null
|
||||
? ''
|
||||
: `\n-# ${literals(strings.bot.commands.auction.body.next, [
|
||||
`<:gold:1317173197082333244> ${data.next_price.value.toLocaleString(
|
||||
interaction.locale,
|
||||
)}`,
|
||||
])}`;
|
||||
const available = literals(
|
||||
strings.bot.commands.auction.body.available,
|
||||
[
|
||||
data.current_count.toLocaleString(interaction.locale),
|
||||
data.initial_count.toLocaleString(interaction.locale),
|
||||
],
|
||||
);
|
||||
const isOut = data.current_count === 0;
|
||||
const outString = isOut ? '~~' : '';
|
||||
const isLow = data.current_count <= WARNING_COUNT;
|
||||
@@ -127,7 +133,7 @@ export const auctionCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
outString
|
||||
}${name} <:gold:1317173197082333244> ${data.price!.value.toLocaleString(
|
||||
interaction.locale,
|
||||
)}${outString}\n-#${isLow ? ' ‼️ ' : ' '}${available}${isOut ? '' : nextLine}`;
|
||||
)}${outString}\n-#${isLow ? ' ‼️ ' : ' '}${available}${isOut ? '' : next}`;
|
||||
});
|
||||
const header = `${title}\n${subtitle}`;
|
||||
const lines = [header, ...body];
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
getWN8Percentile,
|
||||
TankDefinition,
|
||||
} from '@blitzkit/core';
|
||||
import { literals } from '@blitzkit/i18n';
|
||||
import { Locale } from 'discord.js';
|
||||
import { chunk } from 'lodash-es';
|
||||
import * as Breakdown from '../../components/Breakdown';
|
||||
@@ -32,7 +33,7 @@ export async function renderBreakdown(
|
||||
filters: StatFilters,
|
||||
locale: Locale,
|
||||
) {
|
||||
const { t, translate } = translator(locale);
|
||||
const { strings, unwrap } = translator(locale);
|
||||
const awaitedTankDefinitions = await tankDefinitions;
|
||||
const awaitedTankAverages = await blitzStarsTankAverages;
|
||||
const statsInPeriod = await getStatsInPeriod(region, id, start, end, locale);
|
||||
@@ -48,7 +49,7 @@ export async function renderBreakdown(
|
||||
const orderedCareerWN8Full: (number | undefined)[] = [];
|
||||
|
||||
if (tankStats === null) {
|
||||
throw new UserError(t`bot.common.errors.no_tank_stats`);
|
||||
throw new UserError(strings.bot.common.errors.no_tank_stats);
|
||||
}
|
||||
|
||||
filteredOrder.forEach((id) => {
|
||||
@@ -136,21 +137,21 @@ export async function renderBreakdown(
|
||||
<Breakdown.Row
|
||||
key={id}
|
||||
displayType="summary"
|
||||
title={t`bot.commands.breakdown.body.total`}
|
||||
title={strings.bot.commands.breakdown.body.total}
|
||||
stats={[
|
||||
{
|
||||
title: t`bot.commands.breakdown.body.battles`,
|
||||
title: strings.bot.commands.breakdown.body.battles,
|
||||
current: currentBattles,
|
||||
career: careerBattles,
|
||||
},
|
||||
{
|
||||
title: t`bot.commands.breakdown.body.winrate`,
|
||||
title: strings.bot.commands.breakdown.body.winrate,
|
||||
current: `${(100 * currentWinrate).toFixed(2)}%`,
|
||||
career: `${(100 * careerWinrate).toFixed(2)}%`,
|
||||
delta: currentWinrate - careerWinrate,
|
||||
},
|
||||
{
|
||||
title: t`bot.commands.breakdown.body.wn8`,
|
||||
title: strings.bot.commands.breakdown.body.wn8,
|
||||
current:
|
||||
currentWN8 === undefined
|
||||
? undefined
|
||||
@@ -165,7 +166,7 @@ export async function renderBreakdown(
|
||||
: getWN8Percentile(currentWN8),
|
||||
},
|
||||
{
|
||||
title: t`bot.commands.breakdown.body.damage`,
|
||||
title: strings.bot.commands.breakdown.body.damage,
|
||||
current: Math.round(currentDamage).toLocaleString(),
|
||||
career: Math.round(careerDamage).toLocaleString(),
|
||||
delta: currentDamage - careerDamage,
|
||||
@@ -190,17 +191,20 @@ export async function renderBreakdown(
|
||||
class={tankDefinition?.class}
|
||||
type={tankDefinition?.type}
|
||||
title={
|
||||
tankDefinition?.name ??
|
||||
translate('bot.commands.breakdown.body.unknown_tank', [`${id}`])
|
||||
tankDefinition
|
||||
? unwrap(tankDefinition.name)
|
||||
: literals(strings.bot.commands.breakdown.body.unknown_tank, [
|
||||
`${id}`,
|
||||
])
|
||||
}
|
||||
stats={[
|
||||
{
|
||||
title: t`bot.commands.breakdown.body.battles`,
|
||||
title: strings.bot.commands.breakdown.body.battles,
|
||||
current: current.battles.toLocaleString(),
|
||||
career: career.battles.toLocaleString(),
|
||||
},
|
||||
{
|
||||
title: t`bot.commands.breakdown.body.winrate`,
|
||||
title: strings.bot.commands.breakdown.body.winrate,
|
||||
current: `${(100 * (current.wins / current.battles)).toFixed(
|
||||
2,
|
||||
)}%`,
|
||||
@@ -209,7 +213,7 @@ export async function renderBreakdown(
|
||||
current.wins / current.battles - career.wins / career.battles,
|
||||
},
|
||||
{
|
||||
title: t`bot.commands.breakdown.body.wn8`,
|
||||
title: strings.bot.commands.breakdown.body.wn8,
|
||||
current:
|
||||
currentWN8 === undefined
|
||||
? undefined
|
||||
@@ -224,7 +228,7 @@ export async function renderBreakdown(
|
||||
: getWN8Percentile(currentWN8),
|
||||
},
|
||||
{
|
||||
title: t`bot.commands.breakdown.body.damage`,
|
||||
title: strings.bot.commands.breakdown.body.damage,
|
||||
current: Math.round(
|
||||
current.damage_dealt / current.battles,
|
||||
).toLocaleString(),
|
||||
|
||||
@@ -11,17 +11,17 @@ export const debugCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
command: createLocalizedCommand('debug'),
|
||||
|
||||
async handler(interaction) {
|
||||
const { t } = translator(interaction.locale);
|
||||
const { strings } = translator(interaction.locale);
|
||||
const currentTime = new Date().getTime();
|
||||
const uptime = currentTime - executionStart;
|
||||
const list = [
|
||||
[t`bot.commands.debug.body.version`, packageJSON.version],
|
||||
[strings.bot.commands.debug.body.version, packageJSON.version],
|
||||
[
|
||||
t`bot.commands.debug.body.shard`,
|
||||
client.shard?.ids[0] ?? t`bot.commands.debug.body.shard.default`,
|
||||
strings.bot.commands.debug.body.shard.label,
|
||||
client.shard?.ids[0] ?? strings.bot.commands.debug.body.shard.default,
|
||||
],
|
||||
[
|
||||
t`bot.commands.debug.body.uptime`,
|
||||
strings.bot.commands.debug.body.uptime,
|
||||
`${Math.floor((uptime / 1000 / 60 / 60) % 24)}h ${Math.floor(
|
||||
(uptime / 1000 / 60) % 60,
|
||||
)}m ${Math.floor((uptime / 1000) % 60)}s ${Math.floor(
|
||||
@@ -29,7 +29,7 @@ export const debugCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
)}ms`,
|
||||
],
|
||||
];
|
||||
return t`bot.commands.debug.body.title${list
|
||||
return `${strings.bot.commands.debug.body.title}${list
|
||||
.map(([key, value]) => `- ${key}: ${value}`)
|
||||
.join('\n')}`;
|
||||
},
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { getAccountInfo, getClanInfo } from '@blitzkit/core';
|
||||
import { literals } from '@blitzkit/i18n';
|
||||
import { Locale } from 'discord.js';
|
||||
import { CommandWrapper } from '../components/CommandWrapper';
|
||||
import { GenericStats } from '../components/GenericStats';
|
||||
@@ -19,26 +20,31 @@ export const inactiveCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
command: createLocalizedCommand('inactive')
|
||||
.addStringOption(addClanChoices)
|
||||
.addNumberOption((option) => {
|
||||
const { translate } = translator(Locale.EnglishUS);
|
||||
const { strings } = translator(Locale.EnglishUS);
|
||||
|
||||
return option
|
||||
.setName('threshold')
|
||||
.setNameLocalizations(
|
||||
localizationObject('bot.commands.inactive.options.threshold'),
|
||||
localizationObject(
|
||||
(strings) => strings.bot.commands.inactive.options.threshold.name,
|
||||
undefined,
|
||||
true,
|
||||
),
|
||||
)
|
||||
.setDescription(
|
||||
translate('bot.commands.inactive.options.threshold.description'),
|
||||
strings.bot.commands.inactive.options.threshold.description,
|
||||
)
|
||||
.setDescriptionLocalizations(
|
||||
localizationObject(
|
||||
'bot.commands.inactive.options.threshold.description',
|
||||
(strings) =>
|
||||
strings.bot.commands.inactive.options.threshold.description,
|
||||
),
|
||||
)
|
||||
.setMinValue(0);
|
||||
}),
|
||||
|
||||
async handler(interaction) {
|
||||
const { translate } = translator(interaction.locale);
|
||||
const { strings } = translator(interaction.locale);
|
||||
const { region, id } = await resolveClanFromCommand(interaction);
|
||||
const threshold =
|
||||
interaction.options.getNumber('threshold')! ?? DEFAULT_THRESHOLD;
|
||||
@@ -59,7 +65,7 @@ export const inactiveCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
([name, days]) =>
|
||||
[
|
||||
name,
|
||||
translate('bot.commands.inactive.body.listing', [
|
||||
literals(strings.bot.commands.inactive.body.listing, [
|
||||
days.toFixed(0),
|
||||
]),
|
||||
] as [string, string],
|
||||
@@ -71,9 +77,10 @@ export const inactiveCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
<TitleBar
|
||||
title={clanInfo.name}
|
||||
image={`https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clanInfo.emblem_set_id}.png`}
|
||||
description={`${translate('bot.commands.inactive.body.subtitle', [
|
||||
`${threshold}`,
|
||||
])} • ${new Date().toLocaleDateString(interaction.locale)}`}
|
||||
description={`${literals(
|
||||
strings.bot.commands.inactive.body.subtitle,
|
||||
[`${threshold}`],
|
||||
)} • ${new Date().toLocaleDateString(interaction.locale)}`}
|
||||
/>
|
||||
|
||||
{!hasInactiveMembers && (
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
import {
|
||||
getAccountInfo,
|
||||
getClanAccountInfo,
|
||||
linkBlitzAndDiscord,
|
||||
} from '@blitzkit/core';
|
||||
import { getAccountInfo, getClanAccountInfo } from '@blitzkit/core';
|
||||
import { teal } from '@radix-ui/colors';
|
||||
import { Glow } from '../components/AllStatsOverview/components/HeroStat/components/Glow';
|
||||
import { CommandWrapper } from '../components/CommandWrapper';
|
||||
import { linkBlitzAndDiscord } from '../core/db/linkBlitzAndDiscord';
|
||||
import { addUsernameChoices } from '../core/discord/addUsernameChoices';
|
||||
import { autocompleteUsername } from '../core/discord/autocompleteUsername';
|
||||
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
||||
@@ -22,7 +19,7 @@ export const verifyCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
),
|
||||
|
||||
async handler(interaction) {
|
||||
const { t, translate } = translator(interaction.locale);
|
||||
const { strings } = translator(interaction.locale);
|
||||
const { id, region } = await resolvePlayerFromCommand(interaction);
|
||||
const discordId = BigInt(interaction.user.id);
|
||||
const accountInfo = await getAccountInfo(region, id);
|
||||
@@ -120,9 +117,9 @@ export const verifyCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
height: 16,
|
||||
}}
|
||||
/>
|
||||
<span
|
||||
style={{ fontSize: 16 }}
|
||||
>{t`bot.commands.link.body.accounts_linked`}</span>
|
||||
<span style={{ fontSize: 16 }}>
|
||||
{strings.bot.commands.link.body.accounts_linked}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
@@ -174,7 +171,7 @@ export const verifyCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
{clanAccountInfo?.clan
|
||||
? `[${clanAccountInfo?.clan?.tag}] • `
|
||||
: ''}
|
||||
{translate(`common.regions.normal.${region}`)}
|
||||
{strings.common.regions.normal[region]}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -185,8 +182,8 @@ export const verifyCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
</CommandWrapper>,
|
||||
|
||||
embedInfo(
|
||||
t`bot.commands.link.embed.title`,
|
||||
t`bot.commands.link.embed.description`,
|
||||
strings.bot.commands.link.embed.title,
|
||||
strings.bot.commands.link.embed.description,
|
||||
),
|
||||
];
|
||||
},
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
getAccountInfo,
|
||||
getTankStats,
|
||||
} from '@blitzkit/core';
|
||||
import { literals } from '@blitzkit/i18n';
|
||||
import markdownEscape from 'markdown-escape';
|
||||
import {
|
||||
gameDefinitions,
|
||||
@@ -27,14 +28,14 @@ export const ownedTanksCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
.addStringOption(addUsernameChoices),
|
||||
|
||||
async handler(interaction) {
|
||||
const { t, translate } = translator(interaction.locale);
|
||||
const { strings, unwrap } = translator(interaction.locale);
|
||||
const tier = Number(interaction.options.getString('tier'));
|
||||
const { id, region } = await resolvePlayerFromCommand(interaction);
|
||||
const accountInfo = await getAccountInfo(region, id);
|
||||
const tankStats = await getTankStats(region, id);
|
||||
|
||||
if (tankStats === null) {
|
||||
return t`bot.common.errors.no_tank_stats`;
|
||||
return strings.bot.common.errors.no_tank_stats;
|
||||
}
|
||||
|
||||
const filteredTanks = (
|
||||
@@ -59,7 +60,7 @@ export const ownedTanksCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
|
||||
const awaitedTankDefinitions = await tankDefinitions;
|
||||
const awaitedGameDefinitions = await gameDefinitions;
|
||||
const title = translate('bot.commands.owned_tanks.body.title', [
|
||||
const title = literals(strings.bot.commands.owned_tanks.body.title, [
|
||||
markdownEscape(accountInfo.nickname),
|
||||
TIER_ROMAN_NUMERALS[tier],
|
||||
]);
|
||||
@@ -77,7 +78,7 @@ export const ownedTanksCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
)
|
||||
.map(
|
||||
(tank) =>
|
||||
`[${flags[tank.nation]} ${markdownEscape(tank.name)}](<https://blitzkit.app/tools/tankopedia/${tank.id}>)`,
|
||||
`[${flags[tank.nation]} ${markdownEscape(unwrap(tank.name))}](<https://blitzkit.app/tanks/${tank.slug}>)`,
|
||||
);
|
||||
const lines = [title, ...tankList];
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { literals } from '@blitzkit/i18n';
|
||||
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
||||
import { translator } from '../core/localization/translator';
|
||||
import { CommandRegistry } from '../events/interactionCreate';
|
||||
@@ -7,26 +8,26 @@ export const permissionsCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
command: createLocalizedCommand('permissions'),
|
||||
|
||||
async handler(interaction) {
|
||||
const { t, translate } = translator(interaction.locale);
|
||||
const { strings } = translator(interaction.locale);
|
||||
// friday the 13th permissions easter egg
|
||||
const isFridayThe13th =
|
||||
new Date().getDay() === 5 && new Date().getDate() === 13;
|
||||
const permissions = [
|
||||
[
|
||||
interaction.appPermissions?.has('ViewChannel'),
|
||||
t`bot.commands.permissions.body.view_channels`,
|
||||
strings.bot.commands.permissions.body.view_channels,
|
||||
],
|
||||
[
|
||||
interaction.appPermissions?.has('ReadMessageHistory'),
|
||||
t`bot.commands.permissions.body.read_message_history`,
|
||||
strings.bot.commands.permissions.body.read_message_history,
|
||||
],
|
||||
[
|
||||
interaction.appPermissions?.has('AttachFiles'),
|
||||
t`bot.commands.permissions.body.attach_files`,
|
||||
strings.bot.commands.permissions.body.attach_files,
|
||||
],
|
||||
[
|
||||
interaction.appPermissions?.has('UseExternalEmojis'),
|
||||
t`bot.commands.permissions.body.external_emojis`,
|
||||
strings.bot.commands.permissions.body.external_emojis,
|
||||
],
|
||||
];
|
||||
const body = permissions
|
||||
@@ -39,7 +40,7 @@ export const permissionsCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
})
|
||||
.join('\n');
|
||||
|
||||
return translate('bot.commands.permissions.body.title', [body]);
|
||||
return literals(strings.bot.commands.permissions.body.title, [body]);
|
||||
},
|
||||
});
|
||||
});
|
||||
@@ -1,3 +1,4 @@
|
||||
import { literals } from '@blitzkit/i18n';
|
||||
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
||||
import { translator } from '../core/localization/translator';
|
||||
import { CommandRegistry } from '../events/interactionCreate';
|
||||
@@ -12,19 +13,19 @@ export const pingCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
]),
|
||||
|
||||
async handler(interaction) {
|
||||
const { t, translate } = translator(interaction.locale);
|
||||
const { strings } = translator(interaction.locale);
|
||||
const subcommand = interaction.options.getSubcommand();
|
||||
const executionStart = Date.now();
|
||||
|
||||
if (subcommand === 'blitzkit') {
|
||||
await interaction.editReply(t`bot.commands.ping.body.pong`);
|
||||
await interaction.editReply(strings.bot.commands.ping.body.pong);
|
||||
} else {
|
||||
await fetch('https://api.wotblitz.com/');
|
||||
}
|
||||
|
||||
const executionTime = Date.now() - executionStart;
|
||||
interaction.editReply(
|
||||
translate('bot.commands.ping.body.pong_with_time', [
|
||||
literals(strings.bot.commands.ping.body.pong_with_time, [
|
||||
`${Math.round(executionTime)}`,
|
||||
]),
|
||||
);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { getAccountInfo } from '@blitzkit/core';
|
||||
import { literals } from '@blitzkit/i18n';
|
||||
import markdownEscape from 'markdown-escape';
|
||||
import { addUsernameChoices } from '../core/discord/addUsernameChoices';
|
||||
import { autocompleteUsername } from '../core/discord/autocompleteUsername';
|
||||
@@ -15,27 +16,27 @@ export const playerInfoCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
createLocalizedCommand('player-info').addStringOption(addUsernameChoices),
|
||||
|
||||
async handler(interaction) {
|
||||
const { t, translate } = translator(interaction.locale);
|
||||
const { strings } = translator(interaction.locale);
|
||||
const account = await resolvePlayerFromCommand(interaction);
|
||||
const { id, region: region } = account;
|
||||
const accountInfo = await getAccountInfo(region, id);
|
||||
|
||||
return embedInfo(
|
||||
translate('bot.commands.player_info.body.title', [
|
||||
literals(strings.bot.commands.player_info.body.title, [
|
||||
markdownEscape(accountInfo.nickname),
|
||||
]),
|
||||
|
||||
markdownTable([
|
||||
[
|
||||
t`bot.commands.player_info.body.nickname`,
|
||||
strings.bot.commands.player_info.body.nickname,
|
||||
`${accountInfo.nickname}`,
|
||||
],
|
||||
[
|
||||
t`bot.commands.player_info.body.battles`,
|
||||
strings.bot.commands.player_info.body.battles,
|
||||
`${accountInfo.statistics.all.battles}`,
|
||||
],
|
||||
[
|
||||
t`bot.commands.player_info.body.winrate`,
|
||||
strings.bot.commands.player_info.body.winrate,
|
||||
`${(
|
||||
100 *
|
||||
(accountInfo.statistics.all.wins /
|
||||
@@ -44,17 +45,17 @@ export const playerInfoCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
],
|
||||
[],
|
||||
[
|
||||
t`bot.commands.player_info.body.account_id`,
|
||||
strings.bot.commands.player_info.body.account_id,
|
||||
`${accountInfo.account_id}`,
|
||||
],
|
||||
[
|
||||
t`bot.commands.player_info.body.created`,
|
||||
strings.bot.commands.player_info.body.created,
|
||||
new Date(accountInfo.created_at * 1000).toLocaleDateString(
|
||||
interaction.locale,
|
||||
),
|
||||
],
|
||||
[
|
||||
t`bot.commands.player_info.body.last_battle`,
|
||||
strings.bot.commands.player_info.body.last_battle,
|
||||
new Date(accountInfo.last_battle_time * 1000).toLocaleDateString(
|
||||
interaction.locale,
|
||||
),
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
getRatingNeighbors,
|
||||
imgur,
|
||||
} from '@blitzkit/core';
|
||||
import { literals } from '@blitzkit/i18n';
|
||||
import { SlashCommandSubcommandBuilder } from 'discord.js';
|
||||
import markdownEscape from 'markdown-escape';
|
||||
import { Glow } from '../components/AllStatsOverview/components/HeroStat/components/Glow';
|
||||
@@ -53,7 +54,7 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
const subcommand = interaction.options.getSubcommand(true) as
|
||||
| 'season'
|
||||
| 'today';
|
||||
const { t, translate } = translator(interaction.locale);
|
||||
const { strings } = translator(interaction.locale);
|
||||
const { id, region } = await resolvePlayerFromCommand(interaction);
|
||||
const clan = (await getClanAccountInfo(region, id, ['clan']))?.clan;
|
||||
const clanImage = clan ? emblemURL(clan.emblem_set_id) : undefined;
|
||||
@@ -89,7 +90,7 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
const statsB2Array = (await getRatingNeighbors(region, id, 0)).neighbors;
|
||||
|
||||
if (statsB2Array === undefined) {
|
||||
return translate('bot.commands.rating.errors.no_participation', [
|
||||
return literals(strings.bot.commands.rating.errors.no_participation, [
|
||||
markdownEscape(accountInfo.nickname),
|
||||
]);
|
||||
}
|
||||
@@ -98,10 +99,10 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
const league = getLeagueFromScore(statsB2.score);
|
||||
|
||||
if (!statsA) {
|
||||
return t`bot.commands.rating.errors.unrecorded_stats`;
|
||||
return strings.bot.commands.rating.errors.unrecorded_stats;
|
||||
}
|
||||
if (!statsB1) {
|
||||
return translate('bot.commands.rating.errors.no_participation', [
|
||||
return literals(strings.bot.commands.rating.errors.no_participation, [
|
||||
markdownEscape(accountInfo.nickname),
|
||||
]);
|
||||
}
|
||||
@@ -139,9 +140,9 @@ export const ratingCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
<TitleBar
|
||||
title={accountInfo.nickname}
|
||||
image={clanImage}
|
||||
description={`${translate(
|
||||
`bot.commands.rating.body.subtitle.${subcommand}`,
|
||||
)} • ${new Date().toLocaleDateString(interaction.locale)}`}
|
||||
description={`${
|
||||
strings.bot.commands.rating.body.subtitle[subcommand]
|
||||
} • ${new Date().toLocaleDateString(interaction.locale)}`}
|
||||
/>
|
||||
|
||||
<div
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
RatingLeaderboard,
|
||||
Region,
|
||||
} from '@blitzkit/core';
|
||||
import { literals } from '@blitzkit/i18n';
|
||||
import {
|
||||
APIApplicationCommandOptionChoice,
|
||||
Locale,
|
||||
@@ -54,26 +55,32 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
||||
);
|
||||
|
||||
function addOptions(option: SlashCommandSubcommandBuilder) {
|
||||
const { t, translate } = translator(Locale.EnglishUS);
|
||||
const { strings } = translator(Locale.EnglishUS);
|
||||
|
||||
return option
|
||||
.addIntegerOption((option) =>
|
||||
option
|
||||
.setName(t`bot.commands.rating_leaderboard.options.limit`)
|
||||
.setName(strings.bot.commands.rating_leaderboard.options.limit.name)
|
||||
.setNameLocalizations(
|
||||
localizationObject(
|
||||
'bot.commands.rating_leaderboard.options.limit',
|
||||
(strings) =>
|
||||
strings.bot.commands.rating_leaderboard.options.limit.name,
|
||||
undefined,
|
||||
true,
|
||||
),
|
||||
)
|
||||
.setDescription(
|
||||
translate(
|
||||
'bot.commands.rating_leaderboard.options.limit.description',
|
||||
literals(
|
||||
strings.bot.commands.rating_leaderboard.options.limit
|
||||
.description,
|
||||
[`${DEFAULT_LIMIT}`],
|
||||
),
|
||||
)
|
||||
.setDescriptionLocalizations(
|
||||
localizationObject(
|
||||
'bot.commands.rating_leaderboard.options.limit.description',
|
||||
(strings) =>
|
||||
strings.bot.commands.rating_leaderboard.options.limit
|
||||
.description,
|
||||
[`${DEFAULT_LIMIT}`],
|
||||
),
|
||||
)
|
||||
@@ -83,20 +90,26 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
||||
)
|
||||
.addStringOption((option) =>
|
||||
option
|
||||
.setName(t`bot.commands.rating_leaderboard.options.season`)
|
||||
.setName(
|
||||
strings.bot.commands.rating_leaderboard.options.season.name,
|
||||
)
|
||||
.setNameLocalizations(
|
||||
localizationObject(
|
||||
'bot.commands.rating_leaderboard.options.season',
|
||||
(strings) =>
|
||||
strings.bot.commands.rating_leaderboard.options.season.name,
|
||||
undefined,
|
||||
true,
|
||||
),
|
||||
)
|
||||
.setDescription(
|
||||
translate(
|
||||
'bot.commands.rating_leaderboard.options.season.description',
|
||||
),
|
||||
strings.bot.commands.rating_leaderboard.options.season
|
||||
.description,
|
||||
)
|
||||
.setDescriptionLocalizations(
|
||||
localizationObject(
|
||||
'bot.commands.rating_leaderboard.options.season.description',
|
||||
(strings) =>
|
||||
strings.bot.commands.rating_leaderboard.options.season
|
||||
.description,
|
||||
),
|
||||
)
|
||||
.setRequired(false)
|
||||
@@ -108,15 +121,18 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
||||
|
||||
return {
|
||||
name: current
|
||||
? translate(
|
||||
'bot.commands.rating_leaderboard.options.season.choices.current',
|
||||
? literals(
|
||||
strings.bot.commands.rating_leaderboard.options.season
|
||||
.choices.current,
|
||||
[`${number}`],
|
||||
)
|
||||
: `${number}`,
|
||||
value: `${number}`,
|
||||
name_localizations: current
|
||||
? localizationObject(
|
||||
'bot.commands.rating_leaderboard.options.season.choices.current',
|
||||
(strings) =>
|
||||
strings.bot.commands.rating_leaderboard.options
|
||||
.season.choices.current,
|
||||
[`${number}`],
|
||||
)
|
||||
: undefined,
|
||||
@@ -141,33 +157,45 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
||||
modify(option: SlashCommandSubcommandBuilder) {
|
||||
option
|
||||
.addStringOption((option) => {
|
||||
const { t, translate } = translator(Locale.EnglishUS);
|
||||
const { strings } = translator(Locale.EnglishUS);
|
||||
|
||||
return option
|
||||
.setName(t`bot.commands.rating_leaderboard.options.league`)
|
||||
.setName(
|
||||
strings.bot.commands.rating_leaderboard.options.league.name,
|
||||
)
|
||||
.setNameLocalizations(
|
||||
localizationObject(
|
||||
'bot.commands.rating_leaderboard.options.league',
|
||||
(strings) =>
|
||||
strings.bot.commands.rating_leaderboard.options.league
|
||||
.name,
|
||||
undefined,
|
||||
true,
|
||||
),
|
||||
)
|
||||
.setDescription(
|
||||
translate(
|
||||
'bot.commands.rating_leaderboard.options.league.description',
|
||||
),
|
||||
strings.bot.commands.rating_leaderboard.options.league
|
||||
.description,
|
||||
)
|
||||
.setDescriptionLocalizations(
|
||||
localizationObject(
|
||||
'bot.commands.rating_leaderboard.options.league.description',
|
||||
(strings) =>
|
||||
strings.bot.commands.rating_leaderboard.options.league
|
||||
.description,
|
||||
),
|
||||
)
|
||||
.addChoices(
|
||||
...LEAGUES.map(
|
||||
({ name }, value) =>
|
||||
({
|
||||
name: translate(`common.leagues.${name}`),
|
||||
name: (
|
||||
strings.common.leagues as Record<string, string>
|
||||
)[name],
|
||||
value: `${value}`,
|
||||
name_localizations: localizationObject(
|
||||
`common.leagues.${name}`,
|
||||
(strings) =>
|
||||
(
|
||||
strings.common.leagues as Record<string, string>
|
||||
)[name],
|
||||
),
|
||||
}) satisfies APIApplicationCommandOptionChoice<string>,
|
||||
),
|
||||
@@ -183,7 +211,7 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
||||
// BIG TODO: title seems to be in english
|
||||
|
||||
async handler(interaction) {
|
||||
const { t, translate } = translator(interaction.locale);
|
||||
const { strings } = translator(interaction.locale);
|
||||
const subcommand = interaction.options.getSubcommand(true) as
|
||||
| 'league'
|
||||
| 'neighbors';
|
||||
@@ -217,7 +245,8 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
||||
regionRatingInfo !== null &&
|
||||
regionRatingInfo.detail !== undefined
|
||||
) {
|
||||
return t`bot.commands.rating_leaderboard.body.no_ongoing_season`;
|
||||
return strings.bot.commands.rating_leaderboard.body
|
||||
.no_ongoing_season;
|
||||
}
|
||||
|
||||
const result = isCurrentSeason
|
||||
@@ -262,8 +291,9 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
||||
clan: clanData[player.id]?.clan?.tag,
|
||||
nickname:
|
||||
clanData[index]?.account_name ??
|
||||
translate(
|
||||
'bot.commands.rating_leaderboard.body.deleted_player',
|
||||
literals(
|
||||
strings.bot.commands.rating_leaderboard.body
|
||||
.deleted_player,
|
||||
[`${player.id}`],
|
||||
),
|
||||
}) satisfies SimplifiedPlayer,
|
||||
@@ -283,12 +313,14 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
||||
: regionRatingInfo.count) - result[result.length - 1].position;
|
||||
titleName = `${
|
||||
leagueInfo
|
||||
? translate(`common.leagues.${LEAGUES[leagueInfo.index].name}`)
|
||||
? (strings.common.leagues as Record<string, string>)[
|
||||
LEAGUES[leagueInfo.index].name
|
||||
]
|
||||
: ''
|
||||
} - ${translate(`common.regions.short.${region}`)}`;
|
||||
} - ${strings.common.regions.short[region]}`;
|
||||
titleImage = imgur(leagueInfo.icon);
|
||||
titleDescription = translate(
|
||||
'bot.commands.rating_leaderboard.body.top_players',
|
||||
titleDescription = literals(
|
||||
strings.bot.commands.rating_leaderboard.body.top_players,
|
||||
[`${limit}`],
|
||||
);
|
||||
} else {
|
||||
@@ -301,7 +333,8 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
||||
regionRatingInfo !== null &&
|
||||
regionRatingInfo.detail !== undefined
|
||||
) {
|
||||
return t`bot.commands.rating_leaderboard.body.no_ongoing_season`;
|
||||
return strings.bot.commands.rating_leaderboard.body
|
||||
.no_ongoing_season;
|
||||
}
|
||||
|
||||
const accountInfo = await getAccountInfo(region, id);
|
||||
@@ -328,8 +361,9 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
||||
|
||||
if (playerIndex === -1) {
|
||||
throw new UserError(
|
||||
translate(
|
||||
'bot.commands.rating_leaderboard.body.no_participation',
|
||||
literals(
|
||||
strings.bot.commands.rating_leaderboard.body
|
||||
.no_participation,
|
||||
[markdownEscape(accountInfo.nickname), `${season}`],
|
||||
),
|
||||
);
|
||||
@@ -367,7 +401,8 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
||||
? `https://wotblitz-gc.gcdn.co/icons/clanEmblems1x/clan-icon-v2-${clan.emblem_set_id}.png`
|
||||
: undefined;
|
||||
titleName = neighbors ? accountInfo.nickname : '';
|
||||
titleDescription = t`bot.commands.rating_leaderboard.body.neighbors`;
|
||||
titleDescription =
|
||||
strings.bot.commands.rating_leaderboard.body.neighbors;
|
||||
playersAfter =
|
||||
(regionRatingInfo === null
|
||||
? archivedLeaderboard.version!.value.entries.length
|
||||
@@ -416,8 +451,8 @@ export const ratingLeaderboardCommand = new Promise<CommandRegistry>(
|
||||
{items}
|
||||
{playersAfter > 0 && (
|
||||
<Leaderboard.Gap
|
||||
message={translate(
|
||||
'bot.commands.rating_leaderboard.body.more',
|
||||
message={literals(
|
||||
strings.bot.commands.rating_leaderboard.body.more,
|
||||
[`${playersAfter.toLocaleString(interaction.locale)}`],
|
||||
)}
|
||||
/>
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
tankIcon,
|
||||
TIER_ROMAN_NUMERALS,
|
||||
} from '@blitzkit/core';
|
||||
import { Locale } from 'discord.js';
|
||||
import { clamp } from 'lodash-es';
|
||||
import { CommandWrapper } from '../components/CommandWrapper';
|
||||
import { TitleBar } from '../components/TitleBar';
|
||||
@@ -18,6 +19,7 @@ import { RenderConfiguration } from '../core/blitzkit/renderConfiguration';
|
||||
import { blitzStarsTankAverages } from '../core/blitzstars/tankAverages';
|
||||
import { buttonLink } from '../core/discord/buttonLink';
|
||||
import { createLocalizedCommand } from '../core/discord/createLocalizedCommand';
|
||||
import { translator } from '../core/localization/translator';
|
||||
import { CommandRegistry } from '../events/interactionCreate';
|
||||
import { theme } from '../stitches.config';
|
||||
|
||||
@@ -218,11 +220,13 @@ function stat(value: string | number, flex = 2) {
|
||||
}
|
||||
|
||||
async function playerListing(
|
||||
locale: Locale,
|
||||
player: WotInspectorReplayPlayerData,
|
||||
protagonistTeam: boolean,
|
||||
winningTeam: number,
|
||||
recordingPlayer = false,
|
||||
) {
|
||||
const { unwrap } = translator(locale);
|
||||
const awaitedTankAverages = await blitzStarsTankAverages;
|
||||
const awaitedTankDefinitions = await tankDefinitions;
|
||||
const tank = awaitedTankDefinitions.tanks[player.vehicle_descr];
|
||||
@@ -275,7 +279,7 @@ async function playerListing(
|
||||
}}
|
||||
>
|
||||
<img
|
||||
alt={tank.name}
|
||||
alt={unwrap(tank.name)}
|
||||
src={await iconPng(tankIcon(tank.id))}
|
||||
style={{
|
||||
width: 32,
|
||||
@@ -312,7 +316,7 @@ async function playerListing(
|
||||
fontSize: 16,
|
||||
}}
|
||||
>
|
||||
{tank.name}
|
||||
{unwrap(tank.name)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -530,6 +534,7 @@ export const replayCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
)
|
||||
.map((player) =>
|
||||
playerListing(
|
||||
interaction.locale,
|
||||
player,
|
||||
true,
|
||||
replayData.winner_team,
|
||||
@@ -553,7 +558,12 @@ export const replayCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
players
|
||||
.filter((player) => player.team === antagonistTeamId)
|
||||
.map((player) =>
|
||||
playerListing(player, false, replayData.winner_team),
|
||||
playerListing(
|
||||
interaction.locale,
|
||||
player,
|
||||
false,
|
||||
replayData.winner_team,
|
||||
),
|
||||
),
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
TankType,
|
||||
TIER_ROMAN_NUMERALS,
|
||||
} from '@blitzkit/core';
|
||||
import { literals } from '@blitzkit/i18n';
|
||||
import { escapeMarkdown, Locale } from 'discord.js';
|
||||
import { CommandWrapper } from '../components/CommandWrapper';
|
||||
import { TitleBar } from '../components/TitleBar';
|
||||
@@ -28,22 +29,28 @@ import { CommandRegistry } from '../events/interactionCreate';
|
||||
import { theme } from '../stitches.config';
|
||||
|
||||
export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
const { t } = translator(Locale.EnglishUS);
|
||||
const { strings } = translator(Locale.EnglishUS);
|
||||
|
||||
resolve({
|
||||
command: createLocalizedCommand('research')
|
||||
.addStringOption((option) =>
|
||||
option
|
||||
.setName(t`bot.commands.research.options.target_tank`)
|
||||
.setName(strings.bot.commands.research.options.target_tank.name)
|
||||
.setNameLocalizations(
|
||||
localizationObject('bot.commands.research.options.target_tank'),
|
||||
localizationObject(
|
||||
(strings) =>
|
||||
strings.bot.commands.research.options.target_tank.name,
|
||||
undefined,
|
||||
true,
|
||||
),
|
||||
)
|
||||
.setDescription(
|
||||
t`bot.commands.research.options.target_tank.description`,
|
||||
strings.bot.commands.research.options.target_tank.description,
|
||||
)
|
||||
.setDescriptionLocalizations(
|
||||
localizationObject(
|
||||
'bot.commands.research.options.target_tank.description',
|
||||
(strings) =>
|
||||
strings.bot.commands.research.options.target_tank.description,
|
||||
),
|
||||
)
|
||||
.setAutocomplete(true)
|
||||
@@ -51,16 +58,22 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
)
|
||||
.addStringOption((option) =>
|
||||
option
|
||||
.setName(t`bot.commands.research.options.starting_tank`)
|
||||
.setName(strings.bot.commands.research.options.starting_tank.name)
|
||||
.setNameLocalizations(
|
||||
localizationObject('bot.commands.research.options.starting_tank'),
|
||||
localizationObject(
|
||||
(strings) =>
|
||||
strings.bot.commands.research.options.starting_tank.name,
|
||||
undefined,
|
||||
true,
|
||||
),
|
||||
)
|
||||
.setDescription(
|
||||
t`bot.commands.research.options.starting_tank.description`,
|
||||
strings.bot.commands.research.options.starting_tank.description,
|
||||
)
|
||||
.setDescriptionLocalizations(
|
||||
localizationObject(
|
||||
'bot.commands.research.options.starting_tank.description',
|
||||
(strings) =>
|
||||
strings.bot.commands.research.options.starting_tank.description,
|
||||
),
|
||||
)
|
||||
.setAutocomplete(true)
|
||||
@@ -69,7 +82,7 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
.addStringOption(addUsernameChoices),
|
||||
|
||||
async handler(interaction) {
|
||||
const { t, translate } = translator(interaction.locale);
|
||||
const { strings, unwrap } = translator(interaction.locale);
|
||||
const awaitedTankDefinitions = await tankDefinitions;
|
||||
const targetTankId = await resolveTankId(
|
||||
interaction.options.getString('target-tank', true),
|
||||
@@ -90,50 +103,55 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
);
|
||||
|
||||
if (targetTankId === startingTankId) {
|
||||
return translate('bot.commands.research.errors.start_end_equal', [
|
||||
escapeMarkdown(targetTank.name),
|
||||
]);
|
||||
return literals(
|
||||
strings.bot.commands.research.errors.start_end_equal,
|
||||
[escapeMarkdown(unwrap(targetTank.name))],
|
||||
);
|
||||
}
|
||||
|
||||
const startingTank = awaitedTankDefinitions.tanks[startingTankId];
|
||||
|
||||
if (startingTank.tier > targetTank.tier) {
|
||||
return translate('bot.commands.research.errors.unordered', [
|
||||
escapeMarkdown(startingTank.name),
|
||||
escapeMarkdown(targetTank.name),
|
||||
escapeMarkdown(targetTank.name),
|
||||
return literals(strings.bot.commands.research.errors.unordered, [
|
||||
escapeMarkdown(unwrap(startingTank.name)),
|
||||
escapeMarkdown(unwrap(targetTank.name)),
|
||||
escapeMarkdown(unwrap(targetTank.name)),
|
||||
]);
|
||||
}
|
||||
|
||||
if (!targetTankAncestry.includes(startingTankId)) {
|
||||
return translate('bot.commands.research.errors.tanks_not_on_line', [
|
||||
escapeMarkdown(targetTank.name),
|
||||
escapeMarkdown(startingTank.name),
|
||||
]);
|
||||
return literals(
|
||||
strings.bot.commands.research.errors.tanks_not_on_line,
|
||||
[
|
||||
escapeMarkdown(unwrap(targetTank.name)),
|
||||
escapeMarkdown(unwrap(startingTank.name)),
|
||||
],
|
||||
);
|
||||
}
|
||||
} else {
|
||||
if (targetTank.type !== TankType.RESEARCHABLE) {
|
||||
return translate('bot.commands.research.errors.non_tech_tree', [
|
||||
escapeMarkdown(targetTank.name),
|
||||
return literals(strings.bot.commands.research.errors.non_tech_tree, [
|
||||
escapeMarkdown(unwrap(targetTank.name)),
|
||||
]);
|
||||
}
|
||||
|
||||
if (targetTank.tier === 1) {
|
||||
return translate('bot.commands.research.errors.tier_1', [
|
||||
escapeMarkdown(targetTank.name),
|
||||
return literals(strings.bot.commands.research.errors.tier_1, [
|
||||
escapeMarkdown(unwrap(targetTank.name)),
|
||||
]);
|
||||
}
|
||||
|
||||
const tankStats = await getTankStats(region, id);
|
||||
|
||||
if (tankStats === null) {
|
||||
return t`bot.common.errors.no_tank_stats`;
|
||||
return strings.bot.common.errors.no_tank_stats;
|
||||
}
|
||||
|
||||
if (tankStats.some(({ tank_id }) => tank_id === targetTankId)) {
|
||||
return translate('bot.commands.research.errors.already_researched', [
|
||||
escapeMarkdown(targetTank.name),
|
||||
]);
|
||||
return literals(
|
||||
strings.bot.commands.research.errors.already_researched,
|
||||
[escapeMarkdown(unwrap(targetTank.name))],
|
||||
);
|
||||
}
|
||||
|
||||
const foundAncestor = targetTankAncestry.find(
|
||||
@@ -179,15 +197,10 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
|
||||
turret.guns.forEach((gun) => {
|
||||
if (
|
||||
gun.gun_type!.value.base.research_cost !== undefined &&
|
||||
typeof gun.gun_type!.value.base.research_cost
|
||||
.research_cost_type!.value === 'number'
|
||||
gun.research_cost !== undefined &&
|
||||
typeof gun.research_cost.research_cost_type!.value === 'number'
|
||||
) {
|
||||
gunXps.set(
|
||||
gun.gun_type!.value.base.id,
|
||||
gun.gun_type!.value.base.research_cost.research_cost_type!
|
||||
.value,
|
||||
);
|
||||
gunXps.set(gun.id, gun.research_cost.research_cost_type!.value);
|
||||
}
|
||||
});
|
||||
});
|
||||
@@ -247,7 +260,7 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
<TitleBar
|
||||
title={nickname}
|
||||
image={clanImage}
|
||||
description={`${t`bot.commands.research.body.subtitle`} • ${
|
||||
description={`${strings.bot.commands.research.body.subtitle} • ${
|
||||
targetTank.name
|
||||
}`}
|
||||
/>
|
||||
@@ -284,7 +297,7 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
color: theme.colors.textHighContrast,
|
||||
}}
|
||||
>
|
||||
{t`bot.commands.research.body.total`}
|
||||
{strings.bot.commands.research.body.total}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -444,7 +457,7 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
}}
|
||||
>
|
||||
<img
|
||||
alt={tank.name}
|
||||
alt={unwrap(tank.name)}
|
||||
src={TANK_ICONS[tank.class]}
|
||||
width={16}
|
||||
height={16}
|
||||
@@ -455,7 +468,7 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
color: theme.colors.textHighContrast,
|
||||
}}
|
||||
>
|
||||
{tank.name}
|
||||
{unwrap(tank.name)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -489,11 +502,14 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
color: theme.colors.textHighContrast,
|
||||
}}
|
||||
>
|
||||
{translate('bot.commands.research.body.research', [
|
||||
`${costs[index].research?.toLocaleString(
|
||||
interaction.locale,
|
||||
)}`,
|
||||
])}
|
||||
{literals(
|
||||
strings.bot.commands.research.body.research,
|
||||
[
|
||||
`${costs[index].research?.toLocaleString(
|
||||
interaction.locale,
|
||||
)}`,
|
||||
],
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -519,9 +535,10 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
color: theme.colors.textHighContrast,
|
||||
}}
|
||||
>
|
||||
{translate('bot.commands.research.body.upgrades', [
|
||||
costs[index].upgrades.toLocaleString(),
|
||||
])}
|
||||
{literals(
|
||||
strings.bot.commands.research.body.upgrades,
|
||||
[costs[index].upgrades.toLocaleString()],
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
@@ -547,11 +564,14 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
color: theme.colors.textHighContrast,
|
||||
}}
|
||||
>
|
||||
{translate('bot.commands.research.body.purchase', [
|
||||
costs[index].purchase.toLocaleString(
|
||||
interaction.locale,
|
||||
),
|
||||
])}
|
||||
{literals(
|
||||
strings.bot.commands.research.body.purchase,
|
||||
[
|
||||
costs[index].purchase.toLocaleString(
|
||||
interaction.locale,
|
||||
),
|
||||
],
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -576,11 +596,14 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
color: theme.colors.textHighContrast,
|
||||
}}
|
||||
>
|
||||
{translate('bot.commands.research.body.equipment', [
|
||||
costs[index].equipment.toLocaleString(
|
||||
interaction.locale,
|
||||
),
|
||||
])}
|
||||
{literals(
|
||||
strings.bot.commands.research.body.equipment,
|
||||
[
|
||||
costs[index].equipment.toLocaleString(
|
||||
interaction.locale,
|
||||
),
|
||||
],
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -594,7 +617,7 @@ export const researchCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
|
||||
return startingTankRaw
|
||||
? image
|
||||
: [t`bot.commands.research.body.estimation`, image];
|
||||
: [strings.bot.commands.research.body.estimation, image];
|
||||
},
|
||||
|
||||
autocomplete(interaction) {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { ClanList, fetchBlitz, Region } from '@blitzkit/core';
|
||||
import { literals } from '@blitzkit/i18n';
|
||||
import { Locale } from 'discord.js';
|
||||
import markdownEscape from 'markdown-escape';
|
||||
import { addClanChoices } from '../core/discord/addClanChoices';
|
||||
@@ -19,21 +20,27 @@ export const searchClansCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
addClanChoices(option).setAutocomplete(false),
|
||||
)
|
||||
.addIntegerOption((option) => {
|
||||
const { t, translate } = translator(Locale.EnglishUS);
|
||||
const { strings } = translator(Locale.EnglishUS);
|
||||
|
||||
return option
|
||||
.setName(t`bot.commands.search_clans.options.limit`)
|
||||
.setName(strings.bot.commands.search_clans.options.limit.name)
|
||||
.setNameLocalizations(
|
||||
localizationObject('bot.commands.search_clans.options.limit'),
|
||||
localizationObject(
|
||||
(strings) => strings.bot.commands.search_clans.options.limit.name,
|
||||
undefined,
|
||||
true,
|
||||
),
|
||||
)
|
||||
.setDescription(
|
||||
translate('bot.commands.search_clans.options.limit.description', [
|
||||
`${DEFAULT_LIMIT}`,
|
||||
]),
|
||||
literals(
|
||||
strings.bot.commands.search_clans.options.limit.description,
|
||||
[`${DEFAULT_LIMIT}`],
|
||||
),
|
||||
)
|
||||
.setDescriptionLocalizations(
|
||||
localizationObject(
|
||||
'bot.commands.search_clans.options.limit.description',
|
||||
(strings) =>
|
||||
strings.bot.commands.search_clans.options.limit.description,
|
||||
[`${DEFAULT_LIMIT}`],
|
||||
),
|
||||
)
|
||||
@@ -42,7 +49,7 @@ export const searchClansCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
}),
|
||||
|
||||
async handler(interaction) {
|
||||
const { translate } = translator(interaction.locale);
|
||||
const { strings } = translator(interaction.locale);
|
||||
const region = interaction.options.getString('region') as Region;
|
||||
const clan = interaction.options.getString('clan')!;
|
||||
const limit = interaction.options.getInteger('limit') ?? DEFAULT_LIMIT;
|
||||
@@ -52,12 +59,12 @@ export const searchClansCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
});
|
||||
|
||||
return embedInfo(
|
||||
translate('bot.commands.search_clans.body.title', [
|
||||
literals(strings.bot.commands.search_clans.body.title, [
|
||||
markdownEscape(clan),
|
||||
translate(`common.regions.normal.${region}`),
|
||||
strings.common.regions.normal[region],
|
||||
]),
|
||||
clanList.length === 0
|
||||
? translate('bot.commands.search_clans.body.no_results')
|
||||
? strings.bot.commands.search_clans.body.no_results
|
||||
: `\`\`\`\n${clanList
|
||||
.map((clan) => `${clan.name} [${clan.tag}]`)
|
||||
.join('\n')}\n\`\`\``,
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
Region,
|
||||
usernamePattern,
|
||||
} from '@blitzkit/core';
|
||||
import { literals } from '@blitzkit/i18n';
|
||||
import { Locale } from 'discord.js';
|
||||
import markdownEscape from 'markdown-escape';
|
||||
import { addRegionChoices } from '../core/discord/addRegionChoices';
|
||||
@@ -17,7 +18,7 @@ import { CommandRegistry } from '../events/interactionCreate';
|
||||
const DEFAULT_LIMIT = 25;
|
||||
|
||||
export const searchPlayersCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
const { t, translate } = translator(Locale.EnglishUS);
|
||||
const { strings } = translator(Locale.EnglishUS);
|
||||
|
||||
resolve({
|
||||
command: createLocalizedCommand('search-players')
|
||||
@@ -27,18 +28,25 @@ export const searchPlayersCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
)
|
||||
.addIntegerOption((option) =>
|
||||
option
|
||||
.setName(t`bot.commands.search_players.options.limit`)
|
||||
.setName(strings.bot.commands.search_players.options.limit.name)
|
||||
.setNameLocalizations(
|
||||
localizationObject('bot.commands.search_players.options.limit'),
|
||||
localizationObject(
|
||||
(strings) =>
|
||||
strings.bot.commands.search_players.options.limit.name,
|
||||
undefined,
|
||||
true,
|
||||
),
|
||||
)
|
||||
.setDescription(
|
||||
translate('bot.commands.search_players.options.limit.description', [
|
||||
`${DEFAULT_LIMIT}`,
|
||||
]),
|
||||
literals(
|
||||
strings.bot.commands.search_players.options.limit.description,
|
||||
[`${DEFAULT_LIMIT}`],
|
||||
),
|
||||
)
|
||||
.setDescriptionLocalizations(
|
||||
localizationObject(
|
||||
'bot.commands.search_players.options.limit.description',
|
||||
(strings) =>
|
||||
strings.bot.commands.search_players.options.limit.description,
|
||||
[`${DEFAULT_LIMIT}`],
|
||||
),
|
||||
)
|
||||
@@ -47,7 +55,7 @@ export const searchPlayersCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
),
|
||||
|
||||
async handler(interaction) {
|
||||
const { translate } = translator(interaction.locale);
|
||||
const { strings } = translator(interaction.locale);
|
||||
const region = interaction.options.getString('region') as Region;
|
||||
const name = interaction.options.getString('username')!;
|
||||
const limit = interaction.options.getInteger('limit') ?? 25;
|
||||
@@ -60,13 +68,13 @@ export const searchPlayersCommand = new Promise<CommandRegistry>((resolve) => {
|
||||
: [];
|
||||
|
||||
return embedInfo(
|
||||
translate('bot.commands.search_players.body.title', [
|
||||
literals(strings.bot.commands.search_players.body.title, [
|
||||
markdownEscape(trimmedSearch),
|
||||
translate(`common.regions.normal.${region}`),
|
||||
strings.common.regions.normal[region],
|
||||
]),
|
||||
`\`\`\`${
|
||||
players.length === 0
|
||||
? translate('bot.commands.search_players.body.no_results')
|
||||
? strings.bot.commands.search_players.body.no_results
|
||||
: players.map((player) => player.nickname).join('\n')
|
||||
}\`\`\``,
|
||||
);
|
||||
|
||||
@@ -32,7 +32,7 @@ export function AllStatsOverview({
|
||||
locale,
|
||||
supplementaryStats,
|
||||
}: AllStatsOverviewProps) {
|
||||
const { t, translate } = translator(locale);
|
||||
const { strings } = translator(locale);
|
||||
const percentile =
|
||||
typeof supplementaryStats.WN8 === 'number'
|
||||
? getWN8Percentile(supplementaryStats.WN8)
|
||||
@@ -63,18 +63,18 @@ export function AllStatsOverview({
|
||||
}}
|
||||
>
|
||||
<WN8SurroundingStat
|
||||
label={t`bot.common.hero_stats.battles`}
|
||||
label={strings.bot.common.hero_stats.battles}
|
||||
value={stats.battles.toLocaleString()}
|
||||
align={WN8SurroundingStatAlign.Right}
|
||||
/>
|
||||
<WN8SurroundingStat
|
||||
label={t`bot.common.hero_stats.winrate`}
|
||||
label={strings.bot.common.hero_stats.winrate}
|
||||
value={`${(100 * (stats.wins / stats.battles)).toFixed(2)}%`}
|
||||
align={WN8SurroundingStatAlign.Right}
|
||||
padded
|
||||
/>
|
||||
<WN8SurroundingStat
|
||||
label={t`bot.common.hero_stats.damage`}
|
||||
label={strings.bot.common.hero_stats.damage}
|
||||
value={Math.round(
|
||||
stats.damage_dealt / stats.battles,
|
||||
).toLocaleString()}
|
||||
@@ -82,7 +82,7 @@ export function AllStatsOverview({
|
||||
padded
|
||||
/>
|
||||
<WN8SurroundingStat
|
||||
label={t`bot.common.hero_stats.damage_ratio`}
|
||||
label={strings.bot.common.hero_stats.damage_ratio}
|
||||
value={(stats.damage_dealt / stats.damage_received).toFixed(2)}
|
||||
align={WN8SurroundingStatAlign.Right}
|
||||
/>
|
||||
@@ -90,7 +90,7 @@ export function AllStatsOverview({
|
||||
|
||||
<HeroStat
|
||||
value={heroStat}
|
||||
subtitle={translate(`common.wn8_percentile.${percentile}`)}
|
||||
subtitle={strings.common.wn8_percentile[percentile]}
|
||||
color={color}
|
||||
/>
|
||||
|
||||
@@ -103,25 +103,25 @@ export function AllStatsOverview({
|
||||
}}
|
||||
>
|
||||
<WN8SurroundingStat
|
||||
label={t`bot.common.hero_stats.tier`}
|
||||
label={strings.bot.common.hero_stats.tier}
|
||||
value={
|
||||
supplementaryStats.tier ? supplementaryStats.tier.toFixed(2) : '--'
|
||||
}
|
||||
/>
|
||||
<WN8SurroundingStat
|
||||
label={t`bot.common.hero_stats.survival`}
|
||||
label={strings.bot.common.hero_stats.survival}
|
||||
value={`${(100 * (stats.survived_battles / stats.battles)).toFixed(
|
||||
2,
|
||||
)}%`}
|
||||
padded
|
||||
/>
|
||||
<WN8SurroundingStat
|
||||
label={t`bot.common.hero_stats.accuracy`}
|
||||
label={strings.bot.common.hero_stats.accuracy}
|
||||
value={`${(100 * (stats.hits / stats.shots)).toFixed(2)}%`}
|
||||
padded
|
||||
/>
|
||||
<WN8SurroundingStat
|
||||
label={t`bot.common.hero_stats.kills`}
|
||||
label={strings.bot.common.hero_stats.kills}
|
||||
value={(stats.frags / stats.battles).toFixed(2)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -16,8 +16,8 @@ export function CommandWrapper({ children, fat }: CommandWrapperProps) {
|
||||
gap: 16,
|
||||
width: '100%',
|
||||
color: theme.colors.textHighContrast,
|
||||
backgroundColor: theme.colors.appBackground1,
|
||||
position: 'relative',
|
||||
background: theme.colors.appBackground1,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
|
||||
@@ -21,7 +21,7 @@ export function GenericAllStats({
|
||||
supplementaryStats,
|
||||
locale,
|
||||
}: GenericAllStatsProps) {
|
||||
const { t } = translator(locale);
|
||||
const { strings } = translator(locale);
|
||||
const damageRatio = stats.damage_dealt / stats.damage_received;
|
||||
const killsToDeathRatio =
|
||||
stats.frags / (stats.battles - stats.survived_battles);
|
||||
@@ -30,27 +30,28 @@ export function GenericAllStats({
|
||||
<Root>
|
||||
<Row>
|
||||
<Card
|
||||
title={t`bot.commands.full_stats.body.cards.games`}
|
||||
title={strings.bot.commands.full_stats.body.cards.games.title}
|
||||
items={[
|
||||
{
|
||||
label: t`bot.commands.full_stats.body.cards.games.winrate`,
|
||||
label: strings.bot.commands.full_stats.body.cards.games.winrate,
|
||||
value: `${(100 * (stats.wins / stats.battles)).toFixed(2)}%`,
|
||||
},
|
||||
{
|
||||
label: t`bot.commands.full_stats.body.cards.games.battles`,
|
||||
label: strings.bot.commands.full_stats.body.cards.games.battles,
|
||||
value: stats.battles,
|
||||
},
|
||||
{
|
||||
label: t`bot.commands.full_stats.body.cards.games.wins_losses`,
|
||||
label:
|
||||
strings.bot.commands.full_stats.body.cards.games.wins_losses,
|
||||
value: `${stats.wins} / ${stats.losses}`,
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<Card
|
||||
title={t`bot.commands.full_stats.body.cards.efficiency`}
|
||||
title={strings.bot.commands.full_stats.body.cards.efficiency.title}
|
||||
items={[
|
||||
{
|
||||
label: t`bot.commands.full_stats.body.cards.efficiency.wn8`,
|
||||
label: strings.bot.commands.full_stats.body.cards.efficiency.wn8,
|
||||
value:
|
||||
supplementaryStats && isNumber(supplementaryStats.WN8)
|
||||
? supplementaryStats.WN8!.toFixed(0)
|
||||
@@ -60,14 +61,16 @@ export function GenericAllStats({
|
||||
: undefined,
|
||||
},
|
||||
{
|
||||
label: t`bot.commands.full_stats.body.cards.efficiency.survival`,
|
||||
label:
|
||||
strings.bot.commands.full_stats.body.cards.efficiency.survival,
|
||||
value: `${(
|
||||
100 *
|
||||
(stats.survived_battles / stats.battles)
|
||||
).toFixed(2)}%`,
|
||||
},
|
||||
{
|
||||
label: t`bot.commands.full_stats.body.cards.efficiency.accuracy`,
|
||||
label:
|
||||
strings.bot.commands.full_stats.body.cards.efficiency.accuracy,
|
||||
value: `${((stats.hits / stats.shots) * 100).toFixed(2)}%`,
|
||||
},
|
||||
]}
|
||||
@@ -75,14 +78,18 @@ export function GenericAllStats({
|
||||
</Row>
|
||||
<Row>
|
||||
<Card
|
||||
title={t`bot.commands.full_stats.body.cards.lethality`}
|
||||
title={strings.bot.commands.full_stats.body.cards.lethality.title}
|
||||
items={[
|
||||
{
|
||||
label: t`bot.commands.full_stats.body.cards.lethality.average_damage`,
|
||||
label:
|
||||
strings.bot.commands.full_stats.body.cards.lethality
|
||||
.average_damage,
|
||||
value: (stats.damage_dealt / stats.battles).toFixed(0),
|
||||
},
|
||||
{
|
||||
label: t`bot.commands.full_stats.body.cards.lethality.damage_per_tier`,
|
||||
label:
|
||||
strings.bot.commands.full_stats.body.cards.lethality
|
||||
.damage_per_tier,
|
||||
value: supplementaryStats?.tier
|
||||
? (
|
||||
stats.damage_dealt /
|
||||
@@ -92,32 +99,44 @@ export function GenericAllStats({
|
||||
: undefined,
|
||||
},
|
||||
{
|
||||
label: t`bot.commands.full_stats.body.cards.lethality.damage_ratio`,
|
||||
label:
|
||||
strings.bot.commands.full_stats.body.cards.lethality
|
||||
.damage_ratio,
|
||||
value: isFinite(damageRatio) ? damageRatio.toFixed(2) : undefined,
|
||||
},
|
||||
{
|
||||
label: t`bot.commands.full_stats.body.cards.lethality.average_kills`,
|
||||
label:
|
||||
strings.bot.commands.full_stats.body.cards.lethality
|
||||
.average_kills,
|
||||
value: (stats.frags / stats.battles).toFixed(0),
|
||||
},
|
||||
]}
|
||||
/>
|
||||
<Card
|
||||
title={t`bot.commands.full_stats.body.cards.miscellaneous`}
|
||||
title={strings.bot.commands.full_stats.body.cards.miscellaneous.title}
|
||||
items={[
|
||||
{
|
||||
label: t`bot.commands.full_stats.body.cards.miscellaneous.average_tier`,
|
||||
label:
|
||||
strings.bot.commands.full_stats.body.cards.miscellaneous
|
||||
.average_tier,
|
||||
value: supplementaryStats?.tier?.toFixed(2),
|
||||
},
|
||||
{
|
||||
label: t`bot.commands.full_stats.body.cards.miscellaneous.average_spots`,
|
||||
label:
|
||||
strings.bot.commands.full_stats.body.cards.miscellaneous
|
||||
.average_spots,
|
||||
value: (stats.spotted / stats.battles).toFixed(2),
|
||||
},
|
||||
{
|
||||
label: t`bot.commands.full_stats.body.cards.miscellaneous.average_xp`,
|
||||
label:
|
||||
strings.bot.commands.full_stats.body.cards.miscellaneous
|
||||
.average_xp,
|
||||
value: (stats.xp / stats.battles).toFixed(0),
|
||||
},
|
||||
{
|
||||
label: t`bot.commands.full_stats.body.cards.miscellaneous.kills_to_death_ratio`,
|
||||
label:
|
||||
strings.bot.commands.full_stats.body.cards.miscellaneous
|
||||
.kills_to_death_ratio,
|
||||
value: isFinite(killsToDeathRatio)
|
||||
? killsToDeathRatio.toFixed(2)
|
||||
: undefined,
|
||||
|
||||
@@ -12,7 +12,7 @@ interface NoDataProps {
|
||||
}
|
||||
|
||||
export function NoData({ type, locale }: NoDataProps) {
|
||||
const { translate } = translator(locale);
|
||||
const { strings } = translator(locale);
|
||||
|
||||
return (
|
||||
<div
|
||||
@@ -23,7 +23,7 @@ export function NoData({ type, locale }: NoDataProps) {
|
||||
}}
|
||||
>
|
||||
<span style={{ fontSize: 16, color: theme.colors.textLowContrast }}>
|
||||
{translate(`bot.common.no_data.${type}`)}
|
||||
{strings.bot.common.no_data[type]}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { SEARCH_KEYS } from '@blitzkit/core';
|
||||
import { literals } from '@blitzkit/i18n';
|
||||
import { Locale } from 'discord.js';
|
||||
import { go } from 'fuzzysort';
|
||||
import markdownEscape from 'markdown-escape';
|
||||
@@ -11,22 +13,19 @@ export async function resolveTankId(
|
||||
locale: Locale,
|
||||
techTreeOnly = false,
|
||||
) {
|
||||
const { translate } = translator(locale);
|
||||
const { strings } = translator(locale);
|
||||
const number = typeof tank === 'string' ? Number(tank) : tank;
|
||||
|
||||
if (Number.isNaN(number)) {
|
||||
const searchResult = go(
|
||||
`${tank}`,
|
||||
await (techTreeOnly ? tankNamesTechTreeOnly : tankNames),
|
||||
{
|
||||
keys: ['searchableName', 'searchableNameDeburr', 'camouflages'],
|
||||
limit: 1,
|
||||
},
|
||||
{ keys: SEARCH_KEYS, limit: 1 },
|
||||
);
|
||||
|
||||
if (searchResult.length === 0) {
|
||||
throw new UserError(
|
||||
translate('bot.common.errors.tank_name_not_found', [
|
||||
literals(strings.bot.common.errors.tank_name_not_found, [
|
||||
markdownEscape(`${tank}`),
|
||||
]),
|
||||
);
|
||||
@@ -40,7 +39,7 @@ export async function resolveTankId(
|
||||
return number;
|
||||
} else {
|
||||
throw new UserError(
|
||||
translate('bot.common.errors.tank_id_not_found', [`${number}`]),
|
||||
literals(strings.bot.common.errors.tank_id_not_found, [`${number}`]),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,15 +8,15 @@ export async function searchClansAcrossRegionsBotWrapper(
|
||||
locale: Locale,
|
||||
limit?: number,
|
||||
) {
|
||||
const { t } = translator(locale);
|
||||
const { strings } = translator(locale);
|
||||
const trimmed = search.trim();
|
||||
|
||||
if (trimmed.length < 3) {
|
||||
throw new UserError(t`bot.common.errors.query_too_small`);
|
||||
throw new UserError(strings.bot.common.errors.query_too_small);
|
||||
}
|
||||
|
||||
if (trimmed.length > 100) {
|
||||
throw new UserError(t`bot.common.errors.query_too_long`);
|
||||
throw new UserError(strings.bot.common.errors.query_too_long);
|
||||
}
|
||||
|
||||
return await searchClansAcrossRegions(trimmed, limit);
|
||||
|
||||
@@ -8,15 +8,15 @@ export async function searchPlayersAcrossRegionsBotWrapper(
|
||||
locale: Locale,
|
||||
limit?: number,
|
||||
) {
|
||||
const { t } = translator(locale);
|
||||
const { strings } = translator(locale);
|
||||
const trimmed = search.trim();
|
||||
|
||||
if (trimmed.length < 3) {
|
||||
throw new UserError(t`bot.common.errors.query_too_small`);
|
||||
throw new UserError(strings.bot.common.errors.query_too_small);
|
||||
}
|
||||
|
||||
if (trimmed.length > 100) {
|
||||
throw new UserError(t`bot.common.errors.query_too_long`);
|
||||
throw new UserError(strings.bot.common.errors.query_too_long);
|
||||
}
|
||||
|
||||
return await searchPlayersAcrossRegions(trimmed, limit);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { fetchTankDefinitions, TIER_ROMAN_NUMERALS } from '@blitzkit/core';
|
||||
import { literals } from '@blitzkit/i18n';
|
||||
import { Locale } from 'discord.js';
|
||||
import { StatFilters } from '../blitzstars/filterStats';
|
||||
import { translator } from '../localization/translator';
|
||||
@@ -7,22 +8,21 @@ export async function filtersToDescription(
|
||||
{ nation, tier, type, class: tankClass, tank }: StatFilters,
|
||||
locale: Locale,
|
||||
) {
|
||||
const { translate } = translator(locale);
|
||||
const { strings, bkLocale } = translator(locale);
|
||||
const awaitedTankDefinitions = await fetchTankDefinitions();
|
||||
const info: string[] = [];
|
||||
|
||||
// TODO: somehow localize tank names?
|
||||
if (tank) return awaitedTankDefinitions.tanks[tank].name;
|
||||
if (nation) info.push(translate(`common.nations.${nation}`));
|
||||
if (tank) return awaitedTankDefinitions.tanks[tank].name.locales[bkLocale];
|
||||
if (nation)
|
||||
info.push((strings.common.nations as Record<string, string>)[nation]);
|
||||
if (tier) {
|
||||
info.push(
|
||||
translate('bot.common.filters.tier', [TIER_ROMAN_NUMERALS[tier]]),
|
||||
literals(strings.bot.common.filters.tier, [TIER_ROMAN_NUMERALS[tier]]),
|
||||
);
|
||||
}
|
||||
if (tankClass) info.push(translate(`common.tank_class_short.${tankClass}`));
|
||||
if (type) info.push(translate(`common.tree_type.${type}`));
|
||||
if (tankClass) info.push(strings.common.tank_class_short[tankClass]);
|
||||
if (type) info.push(strings.common.tree_type[type]);
|
||||
|
||||
return info.length === 0
|
||||
? translate('bot.common.filters.none')
|
||||
: info.join(', ');
|
||||
return info.length === 0 ? strings.bot.common.filters.none : info.join(', ');
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { idToRegion, usersDatabase } from '@blitzkit/core';
|
||||
import { flagUserActivity } from '@blitzkit/core/src/blitzkit/flagUserActivity';
|
||||
import { idToRegion } from '@blitzkit/core';
|
||||
import { flagUserActivity } from '../db/flagUserActivity';
|
||||
import { usersDatabase } from '../db/users';
|
||||
|
||||
export async function getBlitzFromDiscord(discordId: bigint) {
|
||||
const unique = await usersDatabase.discordUser.findUnique({
|
||||
@@ -8,6 +9,8 @@ export async function getBlitzFromDiscord(discordId: bigint) {
|
||||
|
||||
if (unique === null) return null;
|
||||
|
||||
await flagUserActivity(unique.blitz_id);
|
||||
return { id: unique.blitz_id, region: idToRegion(unique.blitz_id) };
|
||||
const id = Number(unique.blitz_id);
|
||||
|
||||
await flagUserActivity(id);
|
||||
return { id, region: idToRegion(id) };
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { usersDatabase } from '@blitzkit/core';
|
||||
import { usersDatabase } from '../db/users';
|
||||
import { client } from '../discord/client';
|
||||
|
||||
const EXIT_EVENTS = [
|
||||
|
||||
@@ -38,7 +38,7 @@ export async function getTankHistories(
|
||||
locale: Locale,
|
||||
options?: Partial<GetTankHistoriesOptions>,
|
||||
) {
|
||||
const { t } = translator(locale);
|
||||
const { strings } = translator(locale);
|
||||
const mergedOptions = { ...getTankHistoriesDefaultOptions, ...options };
|
||||
const tankHistoriesResponse = await fetch(
|
||||
`https://www.blitzstars.com/api/tankhistories/for/${id}/`,
|
||||
@@ -82,7 +82,7 @@ export async function getTankHistories(
|
||||
const tankStats = await getTankStats(server, id);
|
||||
|
||||
if (tankStats === null) {
|
||||
throw new UserError(t`bot.common.errors.no_tank_stats`);
|
||||
throw new UserError(strings.bot.common.errors.no_tank_stats);
|
||||
}
|
||||
|
||||
tankStats.forEach((tankHistory) => {
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
import { usersDatabase } from '@blitzkit/core';
|
||||
import { usersDatabase } from './users';
|
||||
|
||||
export async function flagUserActivity(blitzId: number) {
|
||||
await usersDatabase.user.upsert({
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
import { usersDatabase } from '@blitzkit/core';
|
||||
import { flagUserActivity } from './flagUserActivity';
|
||||
import { usersDatabase } from './users';
|
||||
|
||||
export async function linkBlitzAndDiscord(discordId: bigint, blitzId: number) {
|
||||
await usersDatabase.discordUser.upsert({
|
||||
@@ -1,3 +1,3 @@
|
||||
import { PrismaClient } from '@prisma/client';
|
||||
import { PrismaClient } from '../../prisma';
|
||||
|
||||
export const usersDatabase = new PrismaClient();
|
||||
@@ -3,14 +3,22 @@ import { translator } from '../localization/translator';
|
||||
import { localizationObject } from './localizationObject';
|
||||
|
||||
export function addClanChoices(option: SlashCommandStringOption) {
|
||||
const { translate } = translator(Locale.EnglishUS);
|
||||
const { strings } = translator(Locale.EnglishUS);
|
||||
|
||||
return option
|
||||
.setName('clan')
|
||||
.setNameLocalizations(localizationObject('bot.common.options.clan'))
|
||||
.setDescription(translate('bot.common.options.clan.description'))
|
||||
.setNameLocalizations(
|
||||
localizationObject(
|
||||
(strings) => strings.bot.common.options.clan.name,
|
||||
undefined,
|
||||
true,
|
||||
),
|
||||
)
|
||||
.setDescription(strings.bot.common.options.clan.description)
|
||||
.setDescriptionLocalizations(
|
||||
localizationObject('bot.common.options.clan.description'),
|
||||
localizationObject(
|
||||
(strings) => strings.bot.common.options.clan.description,
|
||||
),
|
||||
)
|
||||
.setAutocomplete(true)
|
||||
.setMinLength(2)
|
||||
|
||||
@@ -17,30 +17,40 @@ import { localizationObject } from './localizationObject';
|
||||
export function addFilterOptions<
|
||||
Option extends SlashCommandBuilder | SlashCommandSubcommandBuilder,
|
||||
>(option: Option, nations: string[]) {
|
||||
const { translate } = translator(Locale.EnglishUS);
|
||||
const { strings } = translator(Locale.EnglishUS);
|
||||
|
||||
return (
|
||||
option
|
||||
.addStringOption((option) =>
|
||||
option
|
||||
.setName(translate('bot.common.options.filters.nation'))
|
||||
.setName(strings.bot.common.options.filters.nation.name)
|
||||
.setNameLocalizations(
|
||||
localizationObject('bot.common.options.filters.nation'),
|
||||
)
|
||||
.setDescription(
|
||||
translate('bot.common.options.filters.nation.description'),
|
||||
localizationObject(
|
||||
(strings) => strings.bot.common.options.filters.nation.name,
|
||||
undefined,
|
||||
true,
|
||||
),
|
||||
)
|
||||
.setDescription(strings.bot.common.options.filters.nation.description)
|
||||
.setDescriptionLocalizations(
|
||||
localizationObject('bot.common.options.filters.nation.description'),
|
||||
localizationObject(
|
||||
(strings) =>
|
||||
strings.bot.common.options.filters.nation.description,
|
||||
),
|
||||
)
|
||||
.addChoices(
|
||||
...nations.map(
|
||||
(nation) =>
|
||||
({
|
||||
value: nation,
|
||||
name: translate(`common.nations.${nation}`),
|
||||
name: (strings.common.nations as Record<string, string>)[
|
||||
nation
|
||||
],
|
||||
name_localizations: localizationObject(
|
||||
`common.nations.${nation}`,
|
||||
(strings) =>
|
||||
(strings.common.nations as Record<string, string>)[
|
||||
nation
|
||||
],
|
||||
),
|
||||
}) satisfies APIApplicationCommandOptionChoice,
|
||||
),
|
||||
@@ -50,24 +60,28 @@ export function addFilterOptions<
|
||||
.addStringOption((option) => addTierChoices(option).setRequired(false))
|
||||
.addStringOption((option) =>
|
||||
option
|
||||
.setName(translate('bot.common.options.filters.class'))
|
||||
.setName(strings.bot.common.options.filters.class.name)
|
||||
.setNameLocalizations(
|
||||
localizationObject('bot.common.options.filters.class'),
|
||||
)
|
||||
.setDescription(
|
||||
translate('bot.common.options.filters.class.description'),
|
||||
localizationObject(
|
||||
(strings) => strings.bot.common.options.filters.class.name,
|
||||
undefined,
|
||||
true,
|
||||
),
|
||||
)
|
||||
.setDescription(strings.bot.common.options.filters.class.description)
|
||||
.setDescriptionLocalizations(
|
||||
localizationObject('bot.common.options.filters.class.description'),
|
||||
localizationObject(
|
||||
(strings) => strings.bot.common.options.filters.class.description,
|
||||
),
|
||||
)
|
||||
.addChoices(
|
||||
...TANK_CLASSES.map(
|
||||
(tankType) =>
|
||||
({
|
||||
value: `${tankType}`,
|
||||
name: translate(`common.tank_class_short.${tankType}`),
|
||||
name: strings.common.tank_class_short[tankType],
|
||||
name_localizations: localizationObject(
|
||||
`common.tank_class_short.${tankType}`,
|
||||
(strings) => strings.common.tank_class_short[tankType],
|
||||
),
|
||||
}) satisfies APIApplicationCommandOptionChoice,
|
||||
),
|
||||
@@ -76,24 +90,28 @@ export function addFilterOptions<
|
||||
)
|
||||
.addStringOption((option) =>
|
||||
option
|
||||
.setName(translate('bot.common.options.filters.type'))
|
||||
.setName(strings.bot.common.options.filters.type.name)
|
||||
.setNameLocalizations(
|
||||
localizationObject('bot.common.options.filters.type'),
|
||||
)
|
||||
.setDescription(
|
||||
translate('bot.common.options.filters.type.description'),
|
||||
localizationObject(
|
||||
(strings) => strings.bot.common.options.filters.type.name,
|
||||
undefined,
|
||||
true,
|
||||
),
|
||||
)
|
||||
.setDescription(strings.bot.common.options.filters.type.description)
|
||||
.setDescriptionLocalizations(
|
||||
localizationObject('bot.common.options.filters.type.description'),
|
||||
localizationObject(
|
||||
(strings) => strings.bot.common.options.filters.type.description,
|
||||
),
|
||||
)
|
||||
.addChoices(
|
||||
...TANK_TYPES.map(
|
||||
(treeType) =>
|
||||
({
|
||||
value: TANK_TYPE_COMMAND_NAMES[treeType],
|
||||
name: translate(`common.tree_type.${treeType}`),
|
||||
name: strings.common.tree_type[treeType],
|
||||
name_localizations: localizationObject(
|
||||
`common.tree_type.${treeType}`,
|
||||
(strings) => strings.common.tree_type[treeType],
|
||||
),
|
||||
}) satisfies APIApplicationCommandOptionChoice,
|
||||
),
|
||||
|
||||
@@ -16,31 +16,67 @@ export function addPeriodSubCommands(
|
||||
option: SlashCommandSubcommandBuilder,
|
||||
) => SlashCommandSubcommandBuilder = (option) => option,
|
||||
) {
|
||||
const { translate } = translator(Locale.EnglishUS);
|
||||
const { strings } = translator(Locale.EnglishUS);
|
||||
const subcommandNameLocalizations = {
|
||||
today: localizationObject('bot.common.subcommands.today'),
|
||||
30: localizationObject('bot.common.subcommands.30'),
|
||||
60: localizationObject('bot.common.subcommands.60'),
|
||||
90: localizationObject('bot.common.subcommands.90'),
|
||||
career: localizationObject('bot.common.subcommands.career'),
|
||||
custom: localizationObject('bot.common.subcommands.custom'),
|
||||
today: localizationObject(
|
||||
(strings) => strings.bot.common.subcommands.today.name,
|
||||
undefined,
|
||||
true,
|
||||
),
|
||||
30: localizationObject(
|
||||
(strings) => strings.bot.common.subcommands[30].name,
|
||||
undefined,
|
||||
true,
|
||||
),
|
||||
60: localizationObject(
|
||||
(strings) => strings.bot.common.subcommands[60].name,
|
||||
undefined,
|
||||
true,
|
||||
),
|
||||
90: localizationObject(
|
||||
(strings) => strings.bot.common.subcommands[90].name,
|
||||
undefined,
|
||||
true,
|
||||
),
|
||||
career: localizationObject(
|
||||
(strings) => strings.bot.common.subcommands.career.name,
|
||||
undefined,
|
||||
true,
|
||||
),
|
||||
custom: localizationObject(
|
||||
(strings) => strings.bot.common.subcommands.custom.name,
|
||||
undefined,
|
||||
true,
|
||||
),
|
||||
};
|
||||
const subcommandDescriptionLocalizations = {
|
||||
today: localizationObject('bot.common.subcommands.today.description'),
|
||||
30: localizationObject('bot.common.subcommands.30.description'),
|
||||
60: localizationObject('bot.common.subcommands.60.description'),
|
||||
90: localizationObject('bot.common.subcommands.90.description'),
|
||||
career: localizationObject('bot.common.subcommands.career.description'),
|
||||
custom: localizationObject('bot.common.subcommands.custom.description'),
|
||||
today: localizationObject(
|
||||
(strings) => strings.bot.common.subcommands.today.description,
|
||||
),
|
||||
30: localizationObject(
|
||||
(strings) => strings.bot.common.subcommands[30].description,
|
||||
),
|
||||
60: localizationObject(
|
||||
(strings) => strings.bot.common.subcommands[60].description,
|
||||
),
|
||||
90: localizationObject(
|
||||
(strings) => strings.bot.common.subcommands[90].description,
|
||||
),
|
||||
career: localizationObject(
|
||||
(strings) => strings.bot.common.subcommands.career.description,
|
||||
),
|
||||
custom: localizationObject(
|
||||
(strings) => strings.bot.common.subcommands.custom.description,
|
||||
),
|
||||
};
|
||||
|
||||
option
|
||||
.addSubcommand((option) =>
|
||||
extra(
|
||||
option
|
||||
.setName(translate('bot.common.subcommands.today'))
|
||||
.setName(strings.bot.common.subcommands.today.name)
|
||||
.setNameLocalizations(subcommandNameLocalizations.today)
|
||||
.setDescription(translate('bot.common.subcommands.today.description'))
|
||||
.setDescription(strings.bot.common.subcommands.today.description)
|
||||
.setDescriptionLocalizations(
|
||||
subcommandDescriptionLocalizations.today,
|
||||
),
|
||||
@@ -49,38 +85,36 @@ export function addPeriodSubCommands(
|
||||
.addSubcommand((option) =>
|
||||
extra(
|
||||
option
|
||||
.setName(translate('bot.common.subcommands.30'))
|
||||
.setName(strings.bot.common.subcommands[30].name)
|
||||
.setNameLocalizations(subcommandNameLocalizations[30])
|
||||
.setDescription(translate('bot.common.subcommands.30.description'))
|
||||
.setDescription(strings.bot.common.subcommands[30].description)
|
||||
.setDescriptionLocalizations(subcommandDescriptionLocalizations[30]),
|
||||
),
|
||||
)
|
||||
.addSubcommand((option) =>
|
||||
extra(
|
||||
option
|
||||
.setName(translate('bot.common.subcommands.60'))
|
||||
.setName(strings.bot.common.subcommands[60].name)
|
||||
.setNameLocalizations(subcommandNameLocalizations[60])
|
||||
.setDescription(translate('bot.common.subcommands.60.description'))
|
||||
.setDescription(strings.bot.common.subcommands[60].description)
|
||||
.setDescriptionLocalizations(subcommandDescriptionLocalizations[60]),
|
||||
),
|
||||
)
|
||||
.addSubcommand((option) =>
|
||||
extra(
|
||||
option
|
||||
.setName(translate('bot.common.subcommands.90'))
|
||||
.setName(strings.bot.common.subcommands[90].name)
|
||||
.setNameLocalizations(subcommandNameLocalizations[90])
|
||||
.setDescription(translate('bot.common.subcommands.90.description'))
|
||||
.setDescription(strings.bot.common.subcommands[90].description)
|
||||
.setDescriptionLocalizations(subcommandDescriptionLocalizations[90]),
|
||||
),
|
||||
)
|
||||
.addSubcommand((option) =>
|
||||
extra(
|
||||
option
|
||||
.setName(translate('bot.common.subcommands.career'))
|
||||
.setName(strings.bot.common.subcommands.career.name)
|
||||
.setNameLocalizations(subcommandNameLocalizations.career)
|
||||
.setDescription(
|
||||
translate('bot.common.subcommands.career.description'),
|
||||
)
|
||||
.setDescription(strings.bot.common.subcommands.career.description)
|
||||
.setDescriptionLocalizations(
|
||||
subcommandDescriptionLocalizations.career,
|
||||
),
|
||||
@@ -89,31 +123,25 @@ export function addPeriodSubCommands(
|
||||
.addSubcommand((option) =>
|
||||
extra(
|
||||
option
|
||||
.setName(translate('bot.common.subcommands.custom'))
|
||||
.setName(strings.bot.common.subcommands.custom.name)
|
||||
.setNameLocalizations(subcommandNameLocalizations.custom)
|
||||
.setDescription(
|
||||
translate('bot.common.subcommands.custom.description'),
|
||||
)
|
||||
.setDescription(strings.bot.common.subcommands.custom.description)
|
||||
.setDescriptionLocalizations(
|
||||
subcommandDescriptionLocalizations.custom,
|
||||
)
|
||||
.addIntegerOption((option) =>
|
||||
option
|
||||
.setName(translate('bot.common.subcommands.custom.options.start'))
|
||||
.setName(strings.bot.common.subcommands.custom.options.start.name)
|
||||
.setDescription(
|
||||
translate(
|
||||
'bot.common.subcommands.custom.options.start.description',
|
||||
),
|
||||
strings.bot.common.subcommands.custom.options.start.description,
|
||||
)
|
||||
.setRequired(true),
|
||||
)
|
||||
.addIntegerOption((option) =>
|
||||
option
|
||||
.setName(translate('bot.common.subcommands.custom.options.end'))
|
||||
.setName(strings.bot.common.subcommands.custom.options.end.name)
|
||||
.setDescription(
|
||||
translate(
|
||||
'bot.common.subcommands.custom.options.end.description',
|
||||
),
|
||||
strings.bot.common.subcommands.custom.options.end.description,
|
||||
)
|
||||
.setRequired(true),
|
||||
),
|
||||
|
||||
@@ -8,23 +8,31 @@ import { translator } from '../localization/translator';
|
||||
import { localizationObject } from './localizationObject';
|
||||
|
||||
export function addRegionChoices(option: SlashCommandStringOption) {
|
||||
const { t, translate } = translator(Locale.EnglishUS);
|
||||
const { strings } = translator(Locale.EnglishUS);
|
||||
|
||||
return option
|
||||
.setName(t`bot.common.options.region`)
|
||||
.setNameLocalizations(localizationObject('bot.common.options.region'))
|
||||
.setDescription(t`bot.common.options.region.description`)
|
||||
.setName(strings.bot.common.options.region.name)
|
||||
.setNameLocalizations(
|
||||
localizationObject(
|
||||
(strings) => strings.bot.common.options.region.name,
|
||||
undefined,
|
||||
true,
|
||||
),
|
||||
)
|
||||
.setDescription(strings.bot.common.options.region.description)
|
||||
.setDescriptionLocalizations(
|
||||
localizationObject('bot.common.options.region.description'),
|
||||
localizationObject(
|
||||
(strings) => strings.bot.common.options.region.description,
|
||||
),
|
||||
)
|
||||
.addChoices(
|
||||
...REGIONS.map(
|
||||
(region) =>
|
||||
({
|
||||
value: region,
|
||||
name: translate(`common.regions.normal.${region}`),
|
||||
name: strings.common.regions.normal[region],
|
||||
name_localizations: localizationObject(
|
||||
`common.regions.normal.${region}`,
|
||||
(strings) => strings.common.regions.normal[region],
|
||||
),
|
||||
}) satisfies APIApplicationCommandOptionChoice,
|
||||
),
|
||||
|
||||
@@ -3,14 +3,22 @@ import { translator } from '../localization/translator';
|
||||
import { localizationObject } from './localizationObject';
|
||||
|
||||
export function addTankChoices(option: SlashCommandStringOption) {
|
||||
const { translate } = translator(Locale.EnglishUS);
|
||||
const { strings } = translator(Locale.EnglishUS);
|
||||
|
||||
return option
|
||||
.setName(translate('bot.common.options.tank'))
|
||||
.setNameLocalizations(localizationObject('bot.common.options.tank'))
|
||||
.setDescription(translate('bot.common.options.tank.description'))
|
||||
.setName(strings.bot.common.options.tank.name)
|
||||
.setNameLocalizations(
|
||||
localizationObject(
|
||||
(strings) => strings.bot.common.options.tank.name,
|
||||
undefined,
|
||||
true,
|
||||
),
|
||||
)
|
||||
.setDescription(strings.bot.common.options.tank.description)
|
||||
.setDescriptionLocalizations(
|
||||
localizationObject('bot.common.options.tank.description'),
|
||||
localizationObject(
|
||||
(strings) => strings.bot.common.options.tank.description,
|
||||
),
|
||||
)
|
||||
.setAutocomplete(true)
|
||||
.setRequired(true);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { numberToRomanNumeral } from '@blitzkit/core';
|
||||
import { literals } from '@blitzkit/i18n';
|
||||
import {
|
||||
APIApplicationCommandOptionChoice,
|
||||
Locale,
|
||||
@@ -9,26 +10,34 @@ import { translator } from '../localization/translator';
|
||||
import { localizationObject } from './localizationObject';
|
||||
|
||||
export function addTierChoices(option: SlashCommandStringOption) {
|
||||
const { t, translate } = translator(Locale.EnglishUS);
|
||||
const { strings } = translator(Locale.EnglishUS);
|
||||
|
||||
return option
|
||||
.setName(t`bot.common.options.tier`)
|
||||
.setNameLocalizations(localizationObject('bot.common.options.tier'))
|
||||
.setDescription(t`bot.common.options.tier.description`)
|
||||
.setName(strings.bot.common.options.tier.name)
|
||||
.setNameLocalizations(
|
||||
localizationObject(
|
||||
(strings) => strings.bot.common.options.tier.name,
|
||||
undefined,
|
||||
true,
|
||||
),
|
||||
)
|
||||
.setDescription(strings.bot.common.options.tier.description)
|
||||
.setDescriptionLocalizations(
|
||||
localizationObject('bot.common.options.tier.description'),
|
||||
localizationObject(
|
||||
(strings) => strings.bot.common.options.tier.description,
|
||||
),
|
||||
)
|
||||
.setChoices(
|
||||
...range(10, 0).map(
|
||||
(tier) =>
|
||||
({
|
||||
name: translate('bot.common.options.tier.choices.tier', [
|
||||
name: literals(strings.bot.common.options.tier.choices.tier, [
|
||||
`${tier}`,
|
||||
numberToRomanNumeral(tier),
|
||||
]),
|
||||
value: `${tier}`,
|
||||
name_localizations: localizationObject(
|
||||
'bot.common.options.tier.choices.tier',
|
||||
(strings) => strings.bot.common.options.tier.choices.tier,
|
||||
[`${tier}`, numberToRomanNumeral(tier)],
|
||||
),
|
||||
}) satisfies APIApplicationCommandOptionChoice,
|
||||
|
||||
@@ -3,14 +3,22 @@ import { translator } from '../localization/translator';
|
||||
import { localizationObject } from './localizationObject';
|
||||
|
||||
export function addUsernameChoices(option: SlashCommandStringOption) {
|
||||
const { t } = translator(Locale.EnglishUS);
|
||||
const { strings } = translator(Locale.EnglishUS);
|
||||
|
||||
return option
|
||||
.setName(t`bot.common.options.username`)
|
||||
.setNameLocalizations(localizationObject('bot.common.options.username'))
|
||||
.setDescription(t`bot.common.options.username.description`)
|
||||
.setName(strings.bot.common.options.username.name)
|
||||
.setNameLocalizations(
|
||||
localizationObject(
|
||||
(strings) => strings.bot.common.options.username.name,
|
||||
undefined,
|
||||
true,
|
||||
),
|
||||
)
|
||||
.setDescription(strings.bot.common.options.username.description)
|
||||
.setDescriptionLocalizations(
|
||||
localizationObject('bot.common.options.username.description'),
|
||||
localizationObject(
|
||||
(strings) => strings.bot.common.options.username.description,
|
||||
),
|
||||
)
|
||||
.setAutocomplete(true);
|
||||
}
|
||||
@@ -10,7 +10,7 @@ import { DISCORD_CHOICES_MAX_NAME_SIZE, OVERFLOW_SUFFIX } from './constants';
|
||||
export async function autocompleteClan(
|
||||
interaction: AutocompleteInteraction<CacheType>,
|
||||
) {
|
||||
const { translate } = translator(interaction.locale);
|
||||
const { strings } = translator(interaction.locale);
|
||||
const focusedOption = interaction.options.getFocused(true);
|
||||
if (focusedOption.name !== 'clan') return;
|
||||
if (focusedOption.value.length < 2) return interaction.respond([]);
|
||||
@@ -19,9 +19,7 @@ export async function autocompleteClan(
|
||||
await interaction.respond(
|
||||
clans
|
||||
? clans.map((clan) => {
|
||||
let name = `${clan.name} (${translate(
|
||||
`common.regions.short.${clan.region}`,
|
||||
)})`;
|
||||
let name = `${clan.name} (${strings.common.regions.short[clan.region]})`;
|
||||
|
||||
if (name.length > DISCORD_CHOICES_MAX_NAME_SIZE) {
|
||||
const overSize = name.length - DISCORD_CHOICES_MAX_NAME_SIZE;
|
||||
@@ -29,9 +27,7 @@ export async function autocompleteClan(
|
||||
name = `${clan.name.slice(
|
||||
0,
|
||||
clan.name.length - overSize - OVERFLOW_SUFFIX.length,
|
||||
)}${OVERFLOW_SUFFIX} (${translate(
|
||||
`common.regions.short.${clan.region}`,
|
||||
)})`;
|
||||
)}${OVERFLOW_SUFFIX} (${strings.common.regions.short[clan.region]})`;
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import { fetchTankNames, TankType } from '@blitzkit/core';
|
||||
import { fetchTankNames, SEARCH_KEYS, TankType } from '@blitzkit/core';
|
||||
import {
|
||||
ApplicationCommandOptionChoiceData,
|
||||
AutocompleteInteraction,
|
||||
CacheType,
|
||||
} from 'discord.js';
|
||||
import { go } from 'fuzzysort';
|
||||
import { tankNames } from '../blitzkit/nonBlockingPromises';
|
||||
import { translator } from '../localization/translator';
|
||||
import {
|
||||
DISCORD_CHOICES_MAX_NAME_SIZE,
|
||||
OVERFLOW_SUFFIX,
|
||||
} from './autocompleteClan/constants';
|
||||
import { tankNames } from '../blitzkit/nonBlockingPromises';
|
||||
|
||||
export const tankNamesTechTreeOnly = fetchTankNames().then((names) =>
|
||||
names.filter((tank) => tank.treeType === TankType.RESEARCHABLE),
|
||||
@@ -20,6 +21,7 @@ export async function autocompleteTanks(
|
||||
techTreeOnly = false,
|
||||
fields = ['tank'],
|
||||
) {
|
||||
const { unwrap } = translator(interaction.locale);
|
||||
const focusedOption = interaction.options.getFocused(true);
|
||||
if (!fields.includes(focusedOption.name)) return;
|
||||
|
||||
@@ -29,19 +31,16 @@ export async function autocompleteTanks(
|
||||
go(
|
||||
focusedOption.value,
|
||||
await (techTreeOnly ? tankNamesTechTreeOnly : tankNames),
|
||||
{
|
||||
keys: ['searchableName', 'searchableNameDeburr', 'camouflages'],
|
||||
limit: 10,
|
||||
},
|
||||
{ keys: SEARCH_KEYS, limit: 10 },
|
||||
).map(async (item) => {
|
||||
let name = item.obj.searchableName;
|
||||
let name = unwrap(item.obj.searchableName);
|
||||
|
||||
if (name.length > DISCORD_CHOICES_MAX_NAME_SIZE) {
|
||||
const overSize = name.length - DISCORD_CHOICES_MAX_NAME_SIZE;
|
||||
|
||||
name = `${item.obj.searchableName.slice(
|
||||
name = `${unwrap(item.obj.searchableName).slice(
|
||||
0,
|
||||
item.obj.searchableName.length -
|
||||
unwrap(item.obj.searchableName).length -
|
||||
overSize -
|
||||
OVERFLOW_SUFFIX.length,
|
||||
)}${OVERFLOW_SUFFIX}`;
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
export async function autocompleteUsername(
|
||||
interaction: AutocompleteInteraction<CacheType>,
|
||||
) {
|
||||
const { translate } = translator(interaction.locale);
|
||||
const { strings } = translator(interaction.locale);
|
||||
const focusedOption = interaction.options.getFocused(true);
|
||||
if (focusedOption.name !== 'username') return;
|
||||
const players = await searchPlayersAcrossRegions(focusedOption.value);
|
||||
@@ -22,9 +22,9 @@ export async function autocompleteUsername(
|
||||
await interaction.respond(
|
||||
players
|
||||
? players.map((player) => {
|
||||
let name = `${player.nickname} (${translate(
|
||||
`common.regions.short.${player.region}`,
|
||||
)})`;
|
||||
let name = `${player.nickname} (${
|
||||
strings.common.regions.short[player.region]
|
||||
})`;
|
||||
|
||||
if (name.length > DISCORD_CHOICES_MAX_NAME_SIZE) {
|
||||
const overSize = name.length - DISCORD_CHOICES_MAX_NAME_SIZE;
|
||||
@@ -32,9 +32,9 @@ export async function autocompleteUsername(
|
||||
name = `${player.nickname.slice(
|
||||
0,
|
||||
player.nickname.length - overSize - OVERFLOW_SUFFIX.length,
|
||||
)}${OVERFLOW_SUFFIX} (${translate(
|
||||
`common.regions.short.${player.region}`,
|
||||
)})`;
|
||||
)}${OVERFLOW_SUFFIX} (${
|
||||
strings.common.regions.short[player.region]
|
||||
})`;
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -6,13 +6,13 @@ export function buttonRefresh(
|
||||
interaction: ChatInputCommandInteraction,
|
||||
path: string,
|
||||
) {
|
||||
const { t } = translator(interaction.locale);
|
||||
const { strings } = translator(interaction.locale);
|
||||
|
||||
if (
|
||||
interaction.appPermissions?.has('ReadMessageHistory') &&
|
||||
interaction.appPermissions?.has('ViewChannel')
|
||||
) {
|
||||
return buttonPrimary(path, t`bot.common.buttons.refresh`);
|
||||
return buttonPrimary(path, strings.bot.common.buttons.refresh);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { BlitzKitStrings } from '@blitzkit/i18n';
|
||||
import {
|
||||
Locale,
|
||||
SlashCommandBuilder,
|
||||
@@ -23,24 +24,47 @@ export function createLocalizedCommand(
|
||||
| CreateLocalizedCommandSubcommand[]
|
||||
| CreateLocalizedCommandSubcommandGroup[],
|
||||
) {
|
||||
const commandPathItem = command.replaceAll('-', '_');
|
||||
const { translate } = translator(Locale.EnglishUS);
|
||||
const commandPathItem = command.replaceAll(
|
||||
'-',
|
||||
'_',
|
||||
) as keyof BlitzKitStrings['bot']['commands'];
|
||||
const { strings } = translator(Locale.EnglishUS);
|
||||
const slashCommand = new SlashCommandBuilder()
|
||||
.setName(command)
|
||||
.setNameLocalizations(localizationObject(`bot.commands.${commandPathItem}`))
|
||||
.setDescription(translate(`bot.commands.${commandPathItem}.description`))
|
||||
.setNameLocalizations(
|
||||
localizationObject(
|
||||
(strings) => strings.bot.commands[commandPathItem].name,
|
||||
undefined,
|
||||
true,
|
||||
),
|
||||
)
|
||||
.setDescription(strings.bot.commands[commandPathItem].description)
|
||||
.setDescriptionLocalizations(
|
||||
localizationObject(`bot.commands.${commandPathItem}.description`),
|
||||
localizationObject(
|
||||
(strings) => strings.bot.commands[commandPathItem].description,
|
||||
),
|
||||
);
|
||||
|
||||
if (sub) {
|
||||
sub.map((subItem) => {
|
||||
if ('subcommand' in subItem) {
|
||||
const subcommandNameLocalizations = localizationObject(
|
||||
`bot.commands.${commandPathItem}.subcommands.${subItem.subcommand}`,
|
||||
(strings) =>
|
||||
(
|
||||
strings.bot.commands[commandPathItem] as unknown as {
|
||||
subcommands: Record<string, { name: string }>;
|
||||
}
|
||||
).subcommands[subItem.subcommand].name,
|
||||
undefined,
|
||||
true,
|
||||
);
|
||||
const subcommandDescriptionLocalizations = localizationObject(
|
||||
`bot.commands.${commandPathItem}.subcommands.${subItem.subcommand}.description`,
|
||||
(strings) =>
|
||||
(
|
||||
strings.bot.commands[commandPathItem] as unknown as {
|
||||
subcommands: Record<string, { description: string }>;
|
||||
}
|
||||
).subcommands[subItem.subcommand].description,
|
||||
);
|
||||
|
||||
slashCommand.addSubcommand((option) => {
|
||||
@@ -50,18 +74,32 @@ export function createLocalizedCommand(
|
||||
.setName(subItem.subcommand)
|
||||
.setNameLocalizations(subcommandNameLocalizations)
|
||||
.setDescription(
|
||||
translate(
|
||||
`bot.commands.${commandPathItem}.subcommands.${subItem.subcommand}.description`,
|
||||
),
|
||||
(
|
||||
strings.bot.commands[commandPathItem] as unknown as {
|
||||
subcommands: Record<string, { description: string }>;
|
||||
}
|
||||
).subcommands[subItem.subcommand].description,
|
||||
)
|
||||
.setDescriptionLocalizations(subcommandDescriptionLocalizations);
|
||||
});
|
||||
} else {
|
||||
const subcommandNameLocalizations = localizationObject(
|
||||
`bot.commands.${commandPathItem}.groups.${subItem.group}`,
|
||||
(strings) =>
|
||||
(
|
||||
strings.bot.commands[commandPathItem] as unknown as {
|
||||
groups: Record<string, { name: string }>;
|
||||
}
|
||||
).groups[subItem.group].name,
|
||||
undefined,
|
||||
true,
|
||||
);
|
||||
const subcommandDescriptionLocalizations = localizationObject(
|
||||
`bot.commands.${commandPathItem}.groups.${subItem.group}.description`,
|
||||
(strings) =>
|
||||
(
|
||||
strings.bot.commands[commandPathItem] as unknown as {
|
||||
groups: Record<string, { description: string }>;
|
||||
}
|
||||
).groups[subItem.group].description,
|
||||
);
|
||||
|
||||
slashCommand.addSubcommandGroup((option) => {
|
||||
@@ -71,9 +109,11 @@ export function createLocalizedCommand(
|
||||
.setName(subItem.group)
|
||||
.setNameLocalizations(subcommandNameLocalizations)
|
||||
.setDescription(
|
||||
translate(
|
||||
`bot.commands.${commandPathItem}.groups.${subItem.group}.description`,
|
||||
),
|
||||
(
|
||||
strings.bot.commands[commandPathItem] as unknown as {
|
||||
groups: Record<string, { description: string }>;
|
||||
}
|
||||
).groups[subItem.group].description,
|
||||
)
|
||||
.setDescriptionLocalizations(subcommandDescriptionLocalizations);
|
||||
});
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import { literals } from '@blitzkit/i18n';
|
||||
import { Locale } from 'discord.js';
|
||||
import { translator } from '../localization/translator';
|
||||
import { PeriodSize } from './addPeriodSubCommands';
|
||||
|
||||
export function getPeriodOptionName(period: PeriodSize, locale: Locale) {
|
||||
const { translate } = translator(locale);
|
||||
if (period === 'career') return translate('bot.common.periods.career');
|
||||
if (period === 'today') return translate('bot.common.periods.today');
|
||||
return translate('bot.common.periods.days', [period]);
|
||||
const { strings } = translator(locale);
|
||||
if (period === 'career') return strings.bot.common.periods.career;
|
||||
if (period === 'today') return strings.bot.common.periods.today;
|
||||
return literals(strings.bot.common.periods.days, [period]);
|
||||
}
|
||||
@@ -1,14 +1,33 @@
|
||||
import { BlitzKitStrings, literals as literalsFunc } from '@blitzkit/i18n';
|
||||
import { Locale } from 'discord.js';
|
||||
import { SUPPORTED_LOCALES } from '../localization/strings/constants';
|
||||
import { SUPPORTED_LOCALES_DISCORD } from '../localization/strings/constants';
|
||||
import { translator } from '../localization/translator';
|
||||
|
||||
export function localizationObject(path: string, literals?: string[]) {
|
||||
return SUPPORTED_LOCALES.reduce<Partial<Record<Locale, string>>>(
|
||||
const validNameRegex =
|
||||
/^[\p{Ll}\p{Lm}\p{Lo}\p{N}\p{sc=Devanagari}\p{sc=Thai}_-]+$/u;
|
||||
|
||||
export function localizationObject(
|
||||
path: (strings: BlitzKitStrings) => string,
|
||||
literals: string[] = [],
|
||||
strict = false,
|
||||
) {
|
||||
return SUPPORTED_LOCALES_DISCORD.reduce<Partial<Record<Locale, string>>>(
|
||||
(localizations, locale) => {
|
||||
const { translate } = translator(locale);
|
||||
const { strings } = translator(locale);
|
||||
const translation = literalsFunc(path(strings), literals);
|
||||
const isValid =
|
||||
(!strict || validNameRegex.test(translation)) && translation.length > 0;
|
||||
|
||||
if (!isValid) {
|
||||
console.warn(
|
||||
`Invalid localization for ${locale} (${path}): ${translation}; skipping...`,
|
||||
);
|
||||
return localizations;
|
||||
}
|
||||
|
||||
return {
|
||||
...localizations,
|
||||
[locale]: translate(path, literals),
|
||||
[locale]: translation,
|
||||
};
|
||||
},
|
||||
{},
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
import { assertSecret } from '@blitzkit/core';
|
||||
import { ShardingManager } from 'discord.js';
|
||||
|
||||
export const manager = new ShardingManager('dist/bot/workers/bot.js', {
|
||||
token: assertSecret(import.meta.env.DISCORD_TOKEN),
|
||||
});
|
||||
File renamed without changes.
@@ -1,4 +1,5 @@
|
||||
import { Region } from '@blitzkit/core';
|
||||
import { literals } from '@blitzkit/i18n';
|
||||
import { ChatInputCommandInteraction } from 'discord.js';
|
||||
import markdownEscape from 'markdown-escape';
|
||||
import { searchClansAcrossRegionsBotWrapper } from '../blitz/searchClansAcrossRegionsBotWrapper';
|
||||
@@ -10,7 +11,7 @@ export const serverAndIdPattern = /(com|eu|asia)\/[0-9]+/;
|
||||
export async function resolveClanFromCommand(
|
||||
interaction: ChatInputCommandInteraction,
|
||||
) {
|
||||
const { translate } = translator(interaction.locale);
|
||||
const { strings } = translator(interaction.locale);
|
||||
const clan = interaction.options.getString('clan', true);
|
||||
|
||||
if (serverAndIdPattern.test(clan)) {
|
||||
@@ -26,7 +27,9 @@ export async function resolveClanFromCommand(
|
||||
return { region: accounts[0].region, id: accounts[0].clan_id };
|
||||
} else {
|
||||
throw new UserError(
|
||||
translate('bot.common.errors.clan_not_found', [markdownEscape(clan)]),
|
||||
literals(strings.bot.common.errors.clan_not_found, [
|
||||
markdownEscape(clan),
|
||||
]),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { getTimeDaysAgo, Region } from '@blitzkit/core';
|
||||
import { literals } from '@blitzkit/i18n';
|
||||
import { CacheType, ChatInputCommandInteraction } from 'discord.js';
|
||||
import { getPeriodNow } from '../blitzkit/getPeriodNow';
|
||||
import { getPeriodStart } from '../blitzkit/getPeriodStart';
|
||||
@@ -17,7 +18,7 @@ export function resolvePeriodFromCommand(
|
||||
interaction: ChatInputCommandInteraction<CacheType>,
|
||||
forcedPeriod?: PeriodType,
|
||||
) {
|
||||
const { translate } = translator(interaction.locale);
|
||||
const { strings } = translator(interaction.locale);
|
||||
let name: string;
|
||||
let start: number;
|
||||
let end: number;
|
||||
@@ -31,7 +32,7 @@ export function resolvePeriodFromCommand(
|
||||
const startDaysAgoMin = Math.min(startOption, endOption);
|
||||
const endDaysAgoMax = Math.max(startOption, endOption);
|
||||
|
||||
name = translate('bot.common.periods.custom', [
|
||||
name = literals(strings.bot.common.periods.custom, [
|
||||
`${startDaysAgoMin}`,
|
||||
`${endDaysAgoMax}`,
|
||||
]);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { idToRegion, Region } from '@blitzkit/core';
|
||||
import { literals } from '@blitzkit/i18n';
|
||||
import { CacheType, ChatInputCommandInteraction } from 'discord.js';
|
||||
import markdownEscape from 'markdown-escape';
|
||||
import { searchPlayersAcrossRegionsBotWrapper } from '../../blitz/searchPlayersAcrossRegionsBotWrapper';
|
||||
@@ -14,7 +15,7 @@ export interface ResolvedPlayer {
|
||||
export async function resolvePlayerFromCommand(
|
||||
interaction: ChatInputCommandInteraction<CacheType>,
|
||||
) {
|
||||
const { t, translate } = translator(interaction.locale);
|
||||
const { strings } = translator(interaction.locale);
|
||||
const commandUsername = interaction.options.getString('username');
|
||||
|
||||
if (commandUsername !== null) {
|
||||
@@ -36,7 +37,7 @@ export async function resolvePlayerFromCommand(
|
||||
} satisfies ResolvedPlayer;
|
||||
} else {
|
||||
throw new UserError(
|
||||
translate('bot.common.errors.player_not_found', [
|
||||
literals(strings.bot.common.errors.player_not_found, [
|
||||
markdownEscape(commandUsername),
|
||||
]),
|
||||
);
|
||||
@@ -47,6 +48,6 @@ export async function resolvePlayerFromCommand(
|
||||
|
||||
if (account) return account;
|
||||
|
||||
throw new UserError(t`bot.common.errors.player_not_linked`);
|
||||
throw new UserError(strings.bot.common.errors.player_not_linked);
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,25 @@
|
||||
import { DEFAULT_LOCALE, SupportedLocale } from '@blitzkit/i18n';
|
||||
import { Locale } from 'discord.js';
|
||||
|
||||
export const SUPPORTED_LOCALES: Locale[] = [Locale.EnglishUS, Locale.SpanishES];
|
||||
const SUPPORTED_LOCALES_DISCORD_MAP: Record<SupportedLocale, Locale> = {
|
||||
en: Locale.EnglishUS,
|
||||
es: Locale.SpanishES,
|
||||
pt: Locale.PortugueseBR,
|
||||
ru: Locale.Russian,
|
||||
uk: Locale.Ukrainian,
|
||||
zh: Locale.ChineseCN,
|
||||
fr: Locale.French,
|
||||
ja: Locale.Japanese,
|
||||
pl: Locale.Polish,
|
||||
};
|
||||
|
||||
export const SUPPORTED_LOCALES_DISCORD_MAP_INVERSE = Object.fromEntries(
|
||||
Object.entries(SUPPORTED_LOCALES_DISCORD_MAP).map(([k, v]) => [v, k]),
|
||||
) as Record<Locale, SupportedLocale>;
|
||||
|
||||
export const SUPPORTED_LOCALES_DISCORD = Object.values(
|
||||
SUPPORTED_LOCALES_DISCORD_MAP,
|
||||
);
|
||||
|
||||
export const DEFAULT_LOCALE_DISCORD =
|
||||
SUPPORTED_LOCALES_DISCORD_MAP[DEFAULT_LOCALE];
|
||||
@@ -1,19 +0,0 @@
|
||||
import { Locale } from 'discord.js';
|
||||
import { SUPPORTED_LOCALES } from './constants';
|
||||
|
||||
export type TranslationFragmentTree = {
|
||||
[key: string]: TranslationFragment;
|
||||
} & {
|
||||
$?: string;
|
||||
};
|
||||
export type TranslationFragment = string | TranslationFragmentTree;
|
||||
|
||||
export const translations = SUPPORTED_LOCALES.reduce<
|
||||
Partial<Record<Locale, TranslationFragment>>
|
||||
>(
|
||||
(table, locale) => ({
|
||||
...table,
|
||||
[locale]: require(`../../../../../core/lang/${locale}.json`),
|
||||
}),
|
||||
{},
|
||||
);
|
||||
@@ -1,74 +1,20 @@
|
||||
import { STRINGS, unwrapper } from '@blitzkit/i18n';
|
||||
import { Locale } from 'discord.js';
|
||||
import { translations } from './strings';
|
||||
import { SUPPORTED_LOCALES } from './strings/constants';
|
||||
import {
|
||||
DEFAULT_LOCALE_DISCORD,
|
||||
SUPPORTED_LOCALES_DISCORD,
|
||||
SUPPORTED_LOCALES_DISCORD_MAP_INVERSE,
|
||||
} from './strings/constants';
|
||||
|
||||
export function translator(localeRaw: Locale) {
|
||||
const locale =
|
||||
localeRaw !== Locale.EnglishUS && SUPPORTED_LOCALES.includes(localeRaw)
|
||||
localeRaw !== DEFAULT_LOCALE_DISCORD &&
|
||||
SUPPORTED_LOCALES_DISCORD.includes(localeRaw)
|
||||
? localeRaw
|
||||
: Locale.EnglishUS;
|
||||
const strings = translations[locale]!;
|
||||
: DEFAULT_LOCALE_DISCORD;
|
||||
const bkLocale = SUPPORTED_LOCALES_DISCORD_MAP_INVERSE[locale];
|
||||
const strings = STRINGS[bkLocale];
|
||||
const unwrap = unwrapper(bkLocale);
|
||||
|
||||
function translate(path: string, literals?: string[]): string {
|
||||
const pathArray = path.split('.');
|
||||
let fragment = strings;
|
||||
let resolvedString: string;
|
||||
|
||||
for (const pathItem of pathArray) {
|
||||
if (typeof fragment === 'string') {
|
||||
throw new SyntaxError(
|
||||
`Attempted to access string with key "${pathItem}" in "${path}" from within a string instead of an object in locale "${locale}"`,
|
||||
);
|
||||
} else {
|
||||
fragment = fragment[pathItem];
|
||||
|
||||
if (typeof fragment === 'undefined') {
|
||||
const message = `Undefined translation at "${pathItem}" in "${path}" for locale "${locale}"`;
|
||||
|
||||
if (locale === Locale.EnglishUS) {
|
||||
throw new Error(message);
|
||||
} else {
|
||||
console.warn(`${message} falling back to en-US`);
|
||||
return translator(Locale.EnglishUS).translate(path, literals);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof fragment === 'string') {
|
||||
resolvedString = fragment;
|
||||
} else if (fragment.$) {
|
||||
resolvedString = fragment.$!;
|
||||
} else {
|
||||
throw new Error(
|
||||
`Unresolved tree ending for "${path}" in locale "${locale}"`,
|
||||
);
|
||||
}
|
||||
|
||||
if (literals) {
|
||||
const chunks = resolvedString.split('%s');
|
||||
let embeddedString = '';
|
||||
|
||||
chunks.forEach((chunk, index) => {
|
||||
if (index !== 0) embeddedString += literals[index - 1];
|
||||
embeddedString += chunk;
|
||||
});
|
||||
|
||||
return embeddedString;
|
||||
}
|
||||
|
||||
return resolvedString;
|
||||
}
|
||||
|
||||
function t(paths: TemplateStringsArray, ...embeds: string[]) {
|
||||
return paths
|
||||
.map((path, index) =>
|
||||
path.length === 0
|
||||
? ''
|
||||
: `${translate(path)}${index === embeds.length ? '' : embeds[index]}`,
|
||||
)
|
||||
.join('');
|
||||
}
|
||||
|
||||
return { locale, translate, t };
|
||||
return { locale, strings, unwrap, bkLocale };
|
||||
}
|
||||
@@ -8,22 +8,22 @@ import {
|
||||
InteractionReplyOptions,
|
||||
} from 'discord.js';
|
||||
import { InteractionRawReturnable, commands } from '..';
|
||||
import { UserError } from '../../../core/blitzkit/userError';
|
||||
import { buttonLink } from '../../../core/discord/buttonLink';
|
||||
import { embedWarning } from '../../../core/discord/embedWarning';
|
||||
import { normalizeInteractionReturnable } from '../../../core/discord/normalizeInteractionReturnable';
|
||||
import { psa } from '../../../core/discord/psa';
|
||||
import { translator } from '../../../core/localization/translator';
|
||||
import { Writeable } from '../../../types/writable';
|
||||
import { UserError } from '../../../core/blitzkit/userError';
|
||||
|
||||
export async function handleChatInputCommand(
|
||||
interaction: ChatInputCommandInteraction<CacheType>,
|
||||
) {
|
||||
await interaction.deferReply();
|
||||
|
||||
const awaitedCommands = await commands;
|
||||
const registry = awaitedCommands[interaction.commandName];
|
||||
|
||||
await interaction.deferReply();
|
||||
|
||||
try {
|
||||
const returnable = await registry.handler(interaction);
|
||||
|
||||
@@ -126,16 +126,16 @@ export async function handleChatInputCommand(
|
||||
index++;
|
||||
}
|
||||
} catch (error) {
|
||||
const { t } = translator(interaction.locale);
|
||||
const { strings } = translator(interaction.locale);
|
||||
|
||||
const components = [
|
||||
new ActionRowBuilder<ButtonBuilder>().addComponents(
|
||||
new ButtonBuilder()
|
||||
.setLabel(t`bot.common.errors.get_help`)
|
||||
.setLabel(strings.bot.common.errors.get_help)
|
||||
.setURL('https://discord.gg/nDt7AjGJQH')
|
||||
.setStyle(ButtonStyle.Link),
|
||||
),
|
||||
];
|
||||
|
||||
if (error instanceof UserError) {
|
||||
interaction.editReply({
|
||||
content: error.message,
|
||||
@@ -143,9 +143,8 @@ export async function handleChatInputCommand(
|
||||
});
|
||||
} else {
|
||||
console.error(interaction.commandName, error);
|
||||
|
||||
interaction.editReply({
|
||||
content: t`bot.common.errors.uncaught_error`,
|
||||
content: strings.bot.common.errors.uncaught_error,
|
||||
components,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ import {
|
||||
SlashCommandSubcommandsOnlyBuilder,
|
||||
} from 'discord.js';
|
||||
import { aboutCommand } from '../../commands/about';
|
||||
import { auctionCommand } from '../../commands/auction';
|
||||
import { breakdownCommand } from '../../commands/breakdown';
|
||||
import { debugCommand } from '../../commands/debug';
|
||||
import { evolutionCommand } from '../../commands/evolution';
|
||||
@@ -64,20 +63,23 @@ interface CommandRegistryBase {
|
||||
autocomplete?: (interaction: AutocompleteInteraction<CacheType>) => void;
|
||||
button?: (interaction: ButtonInteraction<CacheType>) => InteractionReturnable;
|
||||
}
|
||||
|
||||
interface CommandRegistryImplicit extends CommandRegistryBase {
|
||||
handlesInteraction: true;
|
||||
handler: (interaction: ChatInputCommandInteraction<CacheType>) => void;
|
||||
}
|
||||
|
||||
interface CommandRegistryExplicit extends CommandRegistryBase {
|
||||
handlesInteraction?: false;
|
||||
handler: (
|
||||
interaction: ChatInputCommandInteraction<CacheType>,
|
||||
) => InteractionReturnable;
|
||||
}
|
||||
|
||||
export type CommandRegistry = CommandRegistryImplicit | CommandRegistryExplicit;
|
||||
|
||||
export const COMMANDS_RAW: Promise<CommandRegistry>[] = [
|
||||
auctionCommand,
|
||||
// auctionCommand,
|
||||
permissionsCommand,
|
||||
debugCommand,
|
||||
aboutCommand,
|
||||
@@ -107,10 +109,8 @@ export const commands = Promise.allSettled(COMMANDS_RAW).then((rawCommands) => {
|
||||
`Command ${index} failed to load; skipping...`,
|
||||
registry.reason,
|
||||
);
|
||||
|
||||
return commands;
|
||||
}
|
||||
|
||||
return { ...commands, [registry.value.command.name]: registry.value };
|
||||
},
|
||||
{},
|
||||
@@ -126,9 +126,7 @@ commands.then((awaitedCommands) => {
|
||||
|
||||
rest.put(
|
||||
Routes.applicationCommands(assertSecret(import.meta.env.DISCORD_CLIENT_ID)),
|
||||
{
|
||||
body,
|
||||
},
|
||||
{ body },
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
+67
-64
@@ -1,78 +1,81 @@
|
||||
import { ActivityType } from 'discord.js';
|
||||
import { assertSecret } from '@blitzkit/core';
|
||||
import { ActivityType, ShardingManager } from 'discord.js';
|
||||
import {
|
||||
discoveredIdsDefinitions,
|
||||
tankDefinitions,
|
||||
} from './core/blitzkit/nonBlockingPromises';
|
||||
import { manager } from './core/discord/manager';
|
||||
|
||||
console.log('pre manager event listeners and spawn');
|
||||
let iteration = 0;
|
||||
const interval = setInterval(async () => {
|
||||
iteration++;
|
||||
|
||||
let isFirst = true;
|
||||
const interval = setInterval(() => {
|
||||
if (!isFirst) {
|
||||
console.warn('respawning all shards because manager died');
|
||||
manager.respawnAll();
|
||||
}
|
||||
console.log(`Attempting launch on iteration ${iteration}`);
|
||||
|
||||
isFirst = false;
|
||||
}, 5000);
|
||||
const manager = new ShardingManager('dist/bot/workers/bot.js', {
|
||||
token: assertSecret(import.meta.env.DISCORD_TOKEN),
|
||||
});
|
||||
|
||||
const shards = await manager
|
||||
.on('shardCreate', (shard) => {
|
||||
clearInterval(interval);
|
||||
console.log(`🟡 Launching shard ${shard.id}`);
|
||||
shard.on('ready', () => console.log(`🟢 Launched shard ${shard.id}`));
|
||||
})
|
||||
.spawn();
|
||||
const shards = await manager
|
||||
.on('shardCreate', (shard) => {
|
||||
clearInterval(interval);
|
||||
console.log(`🟡 Launching shard ${shard.id}`);
|
||||
shard.on('ready', () => console.log(`🟢 Launched shard ${shard.id}`));
|
||||
})
|
||||
.spawn();
|
||||
|
||||
console.log('post manager event listeners and spawn');
|
||||
try {
|
||||
let servers = 0;
|
||||
let channels = 0;
|
||||
let users = 0;
|
||||
|
||||
try {
|
||||
let servers = 0;
|
||||
let channels = 0;
|
||||
let users = 0;
|
||||
for (const [, shard] of shards) {
|
||||
const guilds = (await shard.fetchClientValue('guilds.cache')) as any;
|
||||
|
||||
for (const [, shard] of shards) {
|
||||
// wtf is this typing bro???
|
||||
const guilds = (await shard.fetchClientValue('guilds.cache')) as any;
|
||||
servers += guilds.length;
|
||||
|
||||
servers += guilds.length;
|
||||
|
||||
for (const guild of guilds) {
|
||||
channels += guild.channels.length;
|
||||
users += guild.memberCount;
|
||||
for (const guild of guilds) {
|
||||
channels += guild.channels.length;
|
||||
users += guild.memberCount;
|
||||
}
|
||||
}
|
||||
|
||||
const awaitedTankDefinitions = await tankDefinitions;
|
||||
const tanks = Object.values(awaitedTankDefinitions.tanks).length;
|
||||
const awaitedDiscoveredIdsDefinitions = await discoveredIdsDefinitions;
|
||||
const usernames = awaitedDiscoveredIdsDefinitions.count;
|
||||
|
||||
manager.broadcastEval(
|
||||
async (client, { servers, users, channels, tanks, usernames }) => {
|
||||
const bios = [
|
||||
`Living in ${servers.toLocaleString()} servers`,
|
||||
`Serving ${users.toLocaleString()} users`,
|
||||
`Observing ${channels.toLocaleString()} channels`,
|
||||
`Tinkering with ${tanks.toLocaleString()} tanks`,
|
||||
`Memorizing ${usernames.toLocaleString()} usernames`,
|
||||
];
|
||||
|
||||
client.user?.setPresence({
|
||||
activities: [
|
||||
{
|
||||
type: ActivityType.Custom,
|
||||
name: bios[Math.floor(Math.random() * bios.length)],
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
for (const guild of client.guilds.cache.values()) {
|
||||
try {
|
||||
const botMember = await guild.members.fetch(client.user.id);
|
||||
await botMember.setNickname('BlitzKit');
|
||||
} catch {}
|
||||
}
|
||||
},
|
||||
{ context: { servers, channels, users, tanks, usernames } },
|
||||
);
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
'An error occurred when setting up presence, ignoring to keep the process alive',
|
||||
error,
|
||||
);
|
||||
}
|
||||
|
||||
const awaitedTankDefinitions = await tankDefinitions;
|
||||
const tanks = Object.values(awaitedTankDefinitions.tanks).length;
|
||||
const awaitedDiscoveredIdsDefinitions = await discoveredIdsDefinitions;
|
||||
const usernames = awaitedDiscoveredIdsDefinitions.count;
|
||||
|
||||
manager.broadcastEval(
|
||||
(client, { servers, users, channels, tanks, usernames }) => {
|
||||
const bios = [
|
||||
`Living in ${servers.toLocaleString()} servers`,
|
||||
`Serving ${users.toLocaleString()} users`,
|
||||
`Observing ${channels.toLocaleString()} channels`,
|
||||
`Tinkering with ${tanks.toLocaleString()} tanks`,
|
||||
`Memorizing ${usernames.toLocaleString()} usernames`,
|
||||
];
|
||||
|
||||
client.user?.setPresence({
|
||||
activities: [
|
||||
{
|
||||
type: ActivityType.Custom,
|
||||
name: bios[Math.floor(Math.random() * bios.length)],
|
||||
},
|
||||
],
|
||||
});
|
||||
},
|
||||
{ context: { servers, channels, users, tanks, usernames } },
|
||||
);
|
||||
} catch (error) {
|
||||
console.warn(
|
||||
'An error occurred when setting up presence, ignoring to keep the process alive',
|
||||
error,
|
||||
);
|
||||
}
|
||||
}, 5000);
|
||||
@@ -23,7 +23,7 @@ export const theme = {
|
||||
spaces: createSpaces(),
|
||||
|
||||
colors: {
|
||||
...createColors(slateDark),
|
||||
...createColors(mauveDark),
|
||||
...createColors(slateDarkA, 'alpha'),
|
||||
...createColors(slate, 'light'),
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"include": ["src/**/*"]
|
||||
"include": ["src/**/*", "../core/src/blitzkit/supportedLocales.ts", "../i18n/src/unwrapper.ts"]
|
||||
}
|
||||
@@ -1,683 +0,0 @@
|
||||
{
|
||||
"common": {
|
||||
"wn8_percentile": {
|
||||
"0": "Very bad",
|
||||
"1": "Bad",
|
||||
"2": "Below average",
|
||||
"3": "Average",
|
||||
"4": "Above average",
|
||||
"5": "Good",
|
||||
"6": "Very good",
|
||||
"7": "Great",
|
||||
"8": "Unicum",
|
||||
"9": "Super unicum"
|
||||
},
|
||||
|
||||
"bkni_percentile": {
|
||||
"0": "Super malum",
|
||||
"1": "Malum",
|
||||
"2": "Very bad",
|
||||
"3": "Bad",
|
||||
"4": "Below average",
|
||||
"5": "Average",
|
||||
"6": "Above average",
|
||||
"7": "Good",
|
||||
"8": "Very good",
|
||||
"9": "Unicum",
|
||||
"10": "Super unicum"
|
||||
},
|
||||
|
||||
"nations": {
|
||||
"ussr": "U.S.S.R.",
|
||||
"germany": "Germany",
|
||||
"usa": "U.S.A.",
|
||||
"china": "China",
|
||||
"uk": "U.K.",
|
||||
"france": "France",
|
||||
"japan": "Japan",
|
||||
"european": "European Nation",
|
||||
"other": "Hybrid Nation"
|
||||
},
|
||||
|
||||
"nations_adjectives": {
|
||||
"ussr": "U.S.S.R.",
|
||||
"germany": "German",
|
||||
"usa": "U.S.A.",
|
||||
"china": "Chinese",
|
||||
"uk": "U.K.",
|
||||
"france": "French",
|
||||
"japan": "Japanese",
|
||||
"european": "European",
|
||||
"other": "Hybrid"
|
||||
},
|
||||
|
||||
"tank_class_short": {
|
||||
"-1": "unrecognized",
|
||||
"0": "Light",
|
||||
"1": "Medium",
|
||||
"2": "Heavy",
|
||||
"3": "TD"
|
||||
},
|
||||
|
||||
"tank_class_short_plural_lowercase": {
|
||||
"0": "lights",
|
||||
"1": "mediums",
|
||||
"2": "heavies",
|
||||
"3": "TDs"
|
||||
},
|
||||
|
||||
"tank_class_medium": {
|
||||
"-1": "unrecognized",
|
||||
"0": "Light",
|
||||
"1": "Medium",
|
||||
"2": "Heavy",
|
||||
"3": "Tank destroyer"
|
||||
},
|
||||
|
||||
"tree_type": {
|
||||
"-1": "unrecognized",
|
||||
"0": "Tech tree",
|
||||
"1": "Premium",
|
||||
"2": "Collector"
|
||||
},
|
||||
|
||||
"regions": {
|
||||
"normal": {
|
||||
"com": "North America",
|
||||
"eu": "Europe",
|
||||
"asia": "Asia-Pacific"
|
||||
},
|
||||
"short": {
|
||||
"com": "NA",
|
||||
"eu": "EU",
|
||||
"asia": "APAC"
|
||||
}
|
||||
},
|
||||
|
||||
"leagues": {
|
||||
"diamond": "Diamond",
|
||||
"platinum": "Platinum",
|
||||
"gold": "Gold",
|
||||
"silver": "Silver",
|
||||
"bronze": "Bronze"
|
||||
},
|
||||
|
||||
"composite_stats": {
|
||||
"normalized_damage_dealt": "Damage",
|
||||
"normalized_damage_received": "Damage received",
|
||||
"normalized_deaths": "Deathrate",
|
||||
"normalized_frags": "Kills",
|
||||
"normalized_hits": "Hits",
|
||||
"normalized_losses": "Lossrate",
|
||||
"normalized_misses": "Misses",
|
||||
"normalized_shots": "Shots",
|
||||
"normalized_spotted": "Spots",
|
||||
"normalized_survived_battles": "Survival rate",
|
||||
"normalized_win_and_survived": "Winning and surviving rate",
|
||||
"normalized_wins": "Winrate",
|
||||
"normalized_xp": "XP",
|
||||
"normalized_battle_life_time": "Battle time",
|
||||
|
||||
"cumulative_accuracy": "Accuracy",
|
||||
"cumulative_battles": "Battles",
|
||||
"cumulative_capture_points": "Total capture points",
|
||||
"cumulative_damage_dealt": "Total damage",
|
||||
"cumulative_damage_ratio": "Damage ratio",
|
||||
"cumulative_damage_received": "Total damage received",
|
||||
"cumulative_deaths": "Total deaths",
|
||||
"cumulative_dropped_capture_points": "Total dropped capture points",
|
||||
"cumulative_frags": "Total kills",
|
||||
"cumulative_hits": "Total hits",
|
||||
"cumulative_inaccuracy": "Inaccuracy",
|
||||
"cumulative_kills_to_death_ratio": "Kills to death ratio",
|
||||
"cumulative_losses": "Losses",
|
||||
"cumulative_misses": "Total misses",
|
||||
"cumulative_shots": "Total shots",
|
||||
"cumulative_spotted": "Total spots",
|
||||
"cumulative_survived_battles": "Survived battles",
|
||||
"cumulative_win_and_survived": "Won and survived battles",
|
||||
"cumulative_wins": "Wins",
|
||||
"cumulative_xp": "Total XP",
|
||||
"cumulative_wn8": "WN8",
|
||||
"cumulative_battle_life_time": "Total battle time"
|
||||
}
|
||||
},
|
||||
|
||||
"bot": {
|
||||
"common": {
|
||||
"errors": {
|
||||
"clan_not_found": "# Could not find clan\nCouldn't find \"%s\". Try selecting a clan from the search result.",
|
||||
"player_not_found": "# Could not find user\nI couldn't find user \"%s\". Try picking an user from the search result, typing in a valid username, or using the `/link` command.",
|
||||
"player_not_linked": "# Use `/link` to get started\nI don't know who you are but you can tell me today!",
|
||||
"tank_name_not_found": "# Tank not found\nCould not find tank by the name \"%s\".",
|
||||
"tank_id_not_found": "# Tank not found\nCould not find tank by the ID \"%s\". Try typing the name of the tank instead of a number.",
|
||||
"no_tank_stats": "# No tank stats available\nThis player doesn't have any stats available. This may not be the player you are looking for.",
|
||||
"get_help": "Help Discord server",
|
||||
"uncaught_error": "# BlitzKit ran into an error!\nWe're so sorry about this. Feel free to [join the official Discord server](https://discord.gg/nDt7AjGJQH) to get help.",
|
||||
"preview": "# This command is in preview\n\nYou can only access this command in [the official Discord server](https://discord.gg/nDt7AjGJQH). The command will be generally available soon.",
|
||||
"query_too_small": "# Your search is too short\nYour search must be at least 3 characters long.",
|
||||
"query_too_long": "# Your search is too long\nYour search must be at most 100 characters long."
|
||||
},
|
||||
|
||||
"wn8": {
|
||||
"$": "WN8",
|
||||
"very_bad": "Very bad",
|
||||
"bad": "Bad",
|
||||
"below_average": "Below average",
|
||||
"average": "Average",
|
||||
"above_average": "Above average",
|
||||
"good": "Good",
|
||||
"very_good": "Very good",
|
||||
"great": "Great",
|
||||
"unicum": "Unicum",
|
||||
"super_unicum": "Super unicum"
|
||||
},
|
||||
|
||||
"subcommands": {
|
||||
"today": {
|
||||
"$": "today",
|
||||
"description": "Today"
|
||||
},
|
||||
"30": {
|
||||
"$": "30",
|
||||
"description": "30 days"
|
||||
},
|
||||
"60": {
|
||||
"$": "60",
|
||||
"description": "60 days"
|
||||
},
|
||||
"90": {
|
||||
"$": "90",
|
||||
"description": "90 days"
|
||||
},
|
||||
"career": {
|
||||
"$": "career",
|
||||
"description": "Career"
|
||||
},
|
||||
"custom": {
|
||||
"$": "custom",
|
||||
"description": "Custom range",
|
||||
|
||||
"options": {
|
||||
"start": {
|
||||
"$": "start",
|
||||
"description": "Start in number of days ago from today"
|
||||
},
|
||||
"end": {
|
||||
"$": "end",
|
||||
"description": "End in number of days ago from today"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"options": {
|
||||
"clan": {
|
||||
"$": "clan",
|
||||
"description": "The clan name or tag"
|
||||
},
|
||||
|
||||
"tank": {
|
||||
"$": "tank",
|
||||
"description": "The tank to get stats for"
|
||||
},
|
||||
|
||||
"username": {
|
||||
"$": "username",
|
||||
"description": "The Blitz username of the player"
|
||||
},
|
||||
|
||||
"filters": {
|
||||
"nation": {
|
||||
"$": "nation",
|
||||
"description": "Nation"
|
||||
},
|
||||
"class": {
|
||||
"$": "class",
|
||||
"description": "Class"
|
||||
},
|
||||
"type": {
|
||||
"$": "type",
|
||||
"description": "Type"
|
||||
}
|
||||
},
|
||||
|
||||
"region": {
|
||||
"$": "region",
|
||||
"description": "Region"
|
||||
},
|
||||
|
||||
"tier": {
|
||||
"$": "tier",
|
||||
"description": "Tier",
|
||||
|
||||
"choices": {
|
||||
"tier": "Tier %s - %s"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"periods": {
|
||||
"career": "Career",
|
||||
"today": "Today",
|
||||
"days": "%s days",
|
||||
"custom": "%s - %s days"
|
||||
},
|
||||
|
||||
"filters": {
|
||||
"none": "No filters",
|
||||
"tier": "Tier %s"
|
||||
},
|
||||
|
||||
"no_data": {
|
||||
"battles_in_period": "No battles played in this period",
|
||||
"battles_in_season": "No battles played in this season",
|
||||
"players_in_period": "No players in this period",
|
||||
"tanks_found": "No tanks found"
|
||||
},
|
||||
|
||||
"buttons": {
|
||||
"refresh": "Refresh"
|
||||
},
|
||||
|
||||
"hero_stats": {
|
||||
"battles": "Battles",
|
||||
"winrate": "Winrate",
|
||||
"damage": "Damage",
|
||||
"damage_ratio": "Damage ratio",
|
||||
"tier": "Tier",
|
||||
"survival": "Survival",
|
||||
"accuracy": "Accuracy",
|
||||
"kills": "Kills"
|
||||
}
|
||||
},
|
||||
|
||||
"commands": {
|
||||
"auction": {
|
||||
"$": "auction",
|
||||
"description": "Tanks available right now in the auction",
|
||||
|
||||
"body": {
|
||||
"title": "Blitz Auction",
|
||||
"subtitle": "%s available • next prices %s\nBid now: %s",
|
||||
"next": "Next price: %s",
|
||||
"available": "Available: %s / %s"
|
||||
},
|
||||
"errors": {
|
||||
"no_auction": "# No ongoing auction\n\nCurrently, there are no tanks available for purchase in the auction. If you think this is an error, please report this discrepancy in [the official Discord Server](https://discord.gg/nDt7AjGJQH)."
|
||||
},
|
||||
"actions": {
|
||||
"bid": "Bid now"
|
||||
}
|
||||
},
|
||||
|
||||
"replay": {
|
||||
"$": "replay",
|
||||
"description": "Display replay results"
|
||||
},
|
||||
|
||||
"research": {
|
||||
"$": "research",
|
||||
"description": "Lists the expenses in researching a line",
|
||||
|
||||
"options": {
|
||||
"target_tank": {
|
||||
"$": "target-tank",
|
||||
"description": "The final tank to research in the line"
|
||||
},
|
||||
"starting_tank": {
|
||||
"$": "starting-tank",
|
||||
"description": "The starting tank in the line (inferred automatically if not provided)"
|
||||
}
|
||||
},
|
||||
|
||||
"body": {
|
||||
"subtitle": "Research",
|
||||
"total": "Total",
|
||||
"research": "Research: %s",
|
||||
"upgrades": "Upgrades: %s",
|
||||
"purchase": "Purchase: %s",
|
||||
"equipment": "Equipment: %s",
|
||||
"estimation": "# This is an estimation!\n\nThis list may include already researched tanks because of the inaccurate information Wargaming provides. Try providing a `starting-tank` from the line when using the command if you can."
|
||||
},
|
||||
|
||||
"errors": {
|
||||
"non_tech_tree": "# %s is not on the tech tree\n\nYou cannot research a premium/collector tank.",
|
||||
"tier_1": "# %s is a tier I\n\nTier I tanks are always unlocked for free for all players.",
|
||||
"already_researched": "# %s is already researched\n\nTry providing a `starting-tank` when using the command to view the totals for a line you have already researched.",
|
||||
"start_end_equal": "# %s was provided twice\n\nMake sure `starting-tank` and `target-tank` are different.",
|
||||
"tanks_not_on_line": "# %s and %s are not on the same line\n\nMake sure `starting-tank` and `target-tank` are on the same tech-tree line.",
|
||||
"unordered": "# %s higher tiered to %s\n\nMake sure to provide %s as the `starting-tank` instead as it is the lower tiered tank."
|
||||
}
|
||||
},
|
||||
|
||||
"about": {
|
||||
"$": "about",
|
||||
"description": "All the info you need about the bot",
|
||||
"subcommands": {
|
||||
"commands": {
|
||||
"$": "commands",
|
||||
"description": "List of all commands and their descriptions",
|
||||
"body": "# Commands\n\nBlitzKit offers the following commands:\n\n"
|
||||
},
|
||||
"embeds": {
|
||||
"$": "embeds",
|
||||
"description": "How embeds work"
|
||||
},
|
||||
"introduction": {
|
||||
"$": "introduction",
|
||||
"description": "About the bot"
|
||||
},
|
||||
"invite": {
|
||||
"$": "invite",
|
||||
"description": "How to invite the bot"
|
||||
},
|
||||
"timezones": {
|
||||
"$": "timezones",
|
||||
"description": "How BlitzKit infers and uses your timezone"
|
||||
},
|
||||
"credits": {
|
||||
"$": "credits",
|
||||
"description": "People who have helped BlitzKit"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"breakdown": {
|
||||
"$": "breakdown",
|
||||
"description": "A period's breakdown by tanks played",
|
||||
|
||||
"body": {
|
||||
"total": "Total",
|
||||
"battles": "Battles",
|
||||
"wn8": "WN8",
|
||||
"winrate": "Winrate",
|
||||
"damage": "Damage",
|
||||
"unknown_tank": "Unknown tank %s"
|
||||
}
|
||||
},
|
||||
|
||||
"debug": {
|
||||
"$": "debug",
|
||||
"description": "Debug information about the bot",
|
||||
|
||||
"body": {
|
||||
"title": "# Debug\n\n",
|
||||
"version": "Version",
|
||||
"shard": {
|
||||
"$": "Shard",
|
||||
"default": "default"
|
||||
},
|
||||
"uptime": "Uptime"
|
||||
}
|
||||
},
|
||||
|
||||
"evolution": {
|
||||
"$": "evolution",
|
||||
"description": "Evolution of statistics",
|
||||
|
||||
"groups": {
|
||||
"player": {
|
||||
"$": "player",
|
||||
"description": "Player statistics"
|
||||
},
|
||||
|
||||
"tank": {
|
||||
"$": "tank",
|
||||
"description": "Tank statistics"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"inactive": {
|
||||
"$": "inactive",
|
||||
"description": "Lists all inactive players in a clan above a threshold",
|
||||
|
||||
"options": {
|
||||
"threshold": {
|
||||
"$": "threshold",
|
||||
"description": "The number of days inactive (default: %s days)"
|
||||
}
|
||||
},
|
||||
|
||||
"body": {
|
||||
"subtitle": "Inactive for %s+ days",
|
||||
"listing": "%s days"
|
||||
}
|
||||
},
|
||||
|
||||
"full_stats": {
|
||||
"$": "full-stats",
|
||||
"description": "Full in-game statistics",
|
||||
|
||||
"body": {
|
||||
"cards": {
|
||||
"games": {
|
||||
"$": "Games",
|
||||
"winrate": "Winrate",
|
||||
"battles": "Battles",
|
||||
"wins_losses": "Wins / losses"
|
||||
},
|
||||
"efficiency": {
|
||||
"$": "Efficiency",
|
||||
"wn8": "WN8",
|
||||
"survival": "Survival",
|
||||
"accuracy": "Accuracy"
|
||||
},
|
||||
"lethality": {
|
||||
"$": "Lethality",
|
||||
"average_damage": "Average damage",
|
||||
"damage_per_tier": "Damage per tier",
|
||||
"damage_ratio": "Damage ratio",
|
||||
"average_kills": "Average kills"
|
||||
},
|
||||
"miscellaneous": {
|
||||
"$": "Miscellaneous",
|
||||
"average_tier": "Average tier",
|
||||
"average_spots": "Average spots",
|
||||
"average_xp": "Average XP",
|
||||
"kills_to_death_ratio": "Kills to death ratio"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"link": {
|
||||
"$": "link",
|
||||
"description": "Links your Blitz and Discord account",
|
||||
|
||||
"body": {
|
||||
"accounts_linked": "Accounts linked",
|
||||
"no_role_permissions": {
|
||||
"$": "%s failed to verify",
|
||||
"description": "I don't have the permission to manage roles."
|
||||
}
|
||||
},
|
||||
|
||||
"embed": {
|
||||
"title": "Incorrect account?",
|
||||
"description": "Use the command again and select a username from the search results."
|
||||
}
|
||||
},
|
||||
|
||||
"search_clans": {
|
||||
"$": "search-clans",
|
||||
"description": "Search clans",
|
||||
|
||||
"options": {
|
||||
"limit": {
|
||||
"$": "limit",
|
||||
"description": "The max number of clan results (default: %s)"
|
||||
}
|
||||
},
|
||||
|
||||
"body": {
|
||||
"title": "Clan search for %s in region %s",
|
||||
"no_results": "No clans found"
|
||||
}
|
||||
},
|
||||
|
||||
"search_players": {
|
||||
"$": "search-players",
|
||||
"description": "Search players",
|
||||
|
||||
"options": {
|
||||
"limit": {
|
||||
"$": "limit",
|
||||
"description": "The max number of player results (default: %s)"
|
||||
}
|
||||
},
|
||||
|
||||
"body": {
|
||||
"title": "Player search for %s in region %s",
|
||||
"no_results": "No players found"
|
||||
}
|
||||
},
|
||||
|
||||
"rating_leaderboard": {
|
||||
"$": "rating-leaderboard",
|
||||
"description": "Rating battles statistics",
|
||||
|
||||
"subcommands": {
|
||||
"neighbors": {
|
||||
"$": "neighbors",
|
||||
"description": "Neighboring players on the leaderboard"
|
||||
},
|
||||
|
||||
"league": {
|
||||
"$": "league",
|
||||
"description": "Top players of a league"
|
||||
}
|
||||
},
|
||||
|
||||
"options": {
|
||||
"limit": {
|
||||
"$": "limit",
|
||||
"description": "How many neighbors to display (default: %s)"
|
||||
},
|
||||
|
||||
"season": {
|
||||
"$": "season",
|
||||
"description": "Season number (default: current)",
|
||||
|
||||
"choices": {
|
||||
"current": "%s (current)"
|
||||
}
|
||||
},
|
||||
|
||||
"league": {
|
||||
"$": "league",
|
||||
"description": "The league to display"
|
||||
}
|
||||
},
|
||||
|
||||
"body": {
|
||||
"top_players": "Top %s players",
|
||||
"no_participation": "# %s didn't play rating in season %s\n\nThis player did not participate in this season or did not get past calibration.",
|
||||
"no_ongoing_season": "# No ongoing season\n\nThere isn't a currently running rating season.",
|
||||
"deleted_player": "Deleted %s",
|
||||
"neighbors": "Rating neighbors",
|
||||
"more": "+ %s more"
|
||||
}
|
||||
},
|
||||
|
||||
"today": {
|
||||
"$": "today",
|
||||
"description": "Today's played tanks and statistics"
|
||||
},
|
||||
|
||||
"stats": {
|
||||
"$": "stats",
|
||||
"description": "Quick statistics for a period"
|
||||
},
|
||||
|
||||
"owned_tanks": {
|
||||
"$": "owned-tanks",
|
||||
"description": "Shows all own tanks in a tier",
|
||||
|
||||
"body": {
|
||||
"title": "# %s's owned tier %s tanks\n\n"
|
||||
}
|
||||
},
|
||||
|
||||
"permissions": {
|
||||
"$": "permissions",
|
||||
"description": "Checks wether the bot has the required permissions to function",
|
||||
|
||||
"body": {
|
||||
"title": "# Permissions\n\n%s",
|
||||
"view_channels": "View channels: needed to find the message the refresh button was used on",
|
||||
"read_message_history": "Read message history: needed to find the message to refresh",
|
||||
"attach_files": "Attach files: needed to add images to image-based commands",
|
||||
"external_emojis": "External emojis: needed to add national flags and tank class emojis"
|
||||
}
|
||||
},
|
||||
|
||||
"ping": {
|
||||
"$": "ping",
|
||||
"description": "Check wether the bot is alive.",
|
||||
|
||||
"body": {
|
||||
"pong": "Pong 🏓",
|
||||
"pong_with_time": "Pong 🏓 - %sms"
|
||||
},
|
||||
|
||||
"subcommands": {
|
||||
"blitzkit": {
|
||||
"$": "blitzkit",
|
||||
"description": "Ping BlitzKit"
|
||||
},
|
||||
"wotb": {
|
||||
"$": "wotb",
|
||||
"description": "Ping World of Tanks Blitz"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"player_info": {
|
||||
"$": "player-info",
|
||||
"description": "Basic information about a player",
|
||||
|
||||
"body": {
|
||||
"title": "%s's information",
|
||||
"nickname": "Nickname",
|
||||
"battles": "Battles",
|
||||
"winrate": "Winrate",
|
||||
"account_id": "Account ID",
|
||||
"created": "Created",
|
||||
"last_battle": "Last battle"
|
||||
}
|
||||
},
|
||||
|
||||
"rating": {
|
||||
"$": "rating",
|
||||
"description": "Rating player's statistics",
|
||||
|
||||
"subcommands": {
|
||||
"today": {
|
||||
"$": "today",
|
||||
"description": "Today's rating statistics"
|
||||
},
|
||||
"season": {
|
||||
"$": "season",
|
||||
"description": "This season's rating statistics"
|
||||
}
|
||||
},
|
||||
|
||||
"body": {
|
||||
"subtitle": {
|
||||
"today": "Today's rating statistics",
|
||||
"season": "This season's rating statistics"
|
||||
}
|
||||
},
|
||||
|
||||
"errors": {
|
||||
"no_participation": "# %s hasn't played rating\n\nThis player hasn't participated in the rating gamemode this season.",
|
||||
"unrecorded_stats": "# Statistics currently unavailable\n\nWargaming may be currently be facing server downtime. If there is an on-going season, statistics should be available withing 24 hours."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
"website": {}
|
||||
}
|
||||
@@ -1,601 +0,0 @@
|
||||
{
|
||||
"common": {
|
||||
"wn8_percentile": {
|
||||
"0": "Muy malo",
|
||||
"1": "Malo",
|
||||
"2": "Inferior al promedio",
|
||||
"3": "Promedio",
|
||||
"4": "Superior al promedio",
|
||||
"5": "Bueno",
|
||||
"6": "Muy bueno",
|
||||
"7": "Genial",
|
||||
"8": "Unicum",
|
||||
"9": "Super unicum"
|
||||
},
|
||||
"bkni_percentile": {
|
||||
"0": "Super malum",
|
||||
"1": "Malum",
|
||||
"2": "Very bad",
|
||||
"3": "Bad",
|
||||
"4": "Below average",
|
||||
"5": "Average",
|
||||
"6": "Above average",
|
||||
"7": "Good",
|
||||
"8": "Very good",
|
||||
"9": "Unicum",
|
||||
"10": "Super unicum"
|
||||
},
|
||||
"nations": {
|
||||
"ussr": "URSS",
|
||||
"germany": "Alemania",
|
||||
"usa": "EE. UU.",
|
||||
"china": "China",
|
||||
"uk": "Reino Unido",
|
||||
"france": "Francia",
|
||||
"japan": "Japón",
|
||||
"european": "Nación europea",
|
||||
"other": "Nación híbrida"
|
||||
},
|
||||
"nations_adjectives": {
|
||||
"ussr": "U.S.S.R.",
|
||||
"germany": "German",
|
||||
"usa": "U.S.A.",
|
||||
"china": "Chinese",
|
||||
"uk": "U.K.",
|
||||
"france": "French",
|
||||
"japan": "Japanese",
|
||||
"european": "European",
|
||||
"other": "Hybrid"
|
||||
},
|
||||
"tank_class_short": {
|
||||
"-1": "unrecognized",
|
||||
"0": "Light",
|
||||
"1": "Medium",
|
||||
"2": "Heavy",
|
||||
"3": "TD"
|
||||
},
|
||||
"tank_class_short_plural_lowercase": {
|
||||
"0": "lights",
|
||||
"1": "mediums",
|
||||
"2": "heavies",
|
||||
"3": "TDs"
|
||||
},
|
||||
"tank_class_medium": {
|
||||
"-1": "unrecognized",
|
||||
"0": "Light",
|
||||
"1": "Medium",
|
||||
"2": "Heavy",
|
||||
"3": "Tank destroyer"
|
||||
},
|
||||
"tree_type": {
|
||||
"-1": "unrecognized",
|
||||
"0": "Tech tree",
|
||||
"1": "Premium",
|
||||
"2": "Collector"
|
||||
},
|
||||
"regions": {
|
||||
"normal": {
|
||||
"com": "Norteamérica",
|
||||
"eu": "Europa",
|
||||
"asia": "Asia-Pacífico"
|
||||
},
|
||||
"short": {
|
||||
"com": "NA",
|
||||
"eu": "Europa",
|
||||
"asia": "APAC"
|
||||
}
|
||||
},
|
||||
"leagues": {
|
||||
"diamond": "Diamante",
|
||||
"platinum": "Platino",
|
||||
"gold": "Oro",
|
||||
"silver": "Plata",
|
||||
"bronze": "Bronce"
|
||||
},
|
||||
"composite_stats": {
|
||||
"normalized_damage_dealt": "Damage",
|
||||
"normalized_damage_received": "Damage received",
|
||||
"normalized_deaths": "Deathrate",
|
||||
"normalized_frags": "Kills",
|
||||
"normalized_hits": "Hits",
|
||||
"normalized_losses": "Lossrate",
|
||||
"normalized_misses": "Misses",
|
||||
"normalized_shots": "Shots",
|
||||
"normalized_spotted": "Spots",
|
||||
"normalized_survived_battles": "Survival rate",
|
||||
"normalized_win_and_survived": "Winning and surviving rate",
|
||||
"normalized_wins": "Winrate",
|
||||
"normalized_xp": "XP",
|
||||
"normalized_battle_life_time": "Battle time",
|
||||
"cumulative_accuracy": "Accuracy",
|
||||
"cumulative_battles": "Battles",
|
||||
"cumulative_capture_points": "Total capture points",
|
||||
"cumulative_damage_dealt": "Total damage",
|
||||
"cumulative_damage_ratio": "Damage ratio",
|
||||
"cumulative_damage_received": "Total damage received",
|
||||
"cumulative_deaths": "Total deaths",
|
||||
"cumulative_dropped_capture_points": "Total dropped capture points",
|
||||
"cumulative_frags": "Total kills",
|
||||
"cumulative_hits": "Total hits",
|
||||
"cumulative_inaccuracy": "Inaccuracy",
|
||||
"cumulative_kills_to_death_ratio": "Kills to death ratio",
|
||||
"cumulative_losses": "Losses",
|
||||
"cumulative_misses": "Total misses",
|
||||
"cumulative_shots": "Total shots",
|
||||
"cumulative_spotted": "Total spots",
|
||||
"cumulative_survived_battles": "Survived battles",
|
||||
"cumulative_win_and_survived": "Won and survived battles",
|
||||
"cumulative_wins": "Wins",
|
||||
"cumulative_xp": "Total XP",
|
||||
"cumulative_wn8": "WN8",
|
||||
"cumulative_battle_life_time": "Total battle time"
|
||||
}
|
||||
},
|
||||
"bot": {
|
||||
"common": {
|
||||
"errors": {
|
||||
"clan_not_found": "# No se pudo encontrar el clan\nNo se pudo encontrar \"%s\". Prueba seleccionando un clan de los resultados de búsqueda.",
|
||||
"player_not_found": "# No se pudo encontrar el usuario\nNo pude encontrar al usuario \"%s\". Prueba eligiendo un usuario de los resultados de búsqueda, escribiendo un nombre de usuario aceptable o usando el comando `/vincular`.",
|
||||
"player_not_linked": "# No sé quién eres\nUsa el comando `/vincular` para comenzar.",
|
||||
"tank_name_not_found": "# No se pudo encontrar el tanque\nNo se pudo encontrar el tanque con el nombre \"%s\".",
|
||||
"tank_id_not_found": "# Tanque no encontrado\nNo se pudo encontrar al tanque del ID \"%s\". Prueba escribiendo el nombre del tanque en vez de un número.",
|
||||
"no_tank_stats": "# No hay estadísticas de tanque disponibles\nEste jugador no tiene estadísticas disponibles. Este podría no ser el jugador que estás buscando.",
|
||||
"get_help": "Servidor de ayuda de Discord",
|
||||
"uncaught_error": "# ¡Blitzkrieg sufrió un error!\nLo sentimos mucho. Siéntete libre de [unirte al servidor oficial de Discord](https://discord.gg/nDt7AjGJQH) para obtener ayuda.",
|
||||
"preview": "# Este comando es una vista previa\n\nSolo puedes acceder a este comando en [el servidor oficial de Discord](https://discord.gg/nDt7AjGJQH). Generalmente este comando estará disponible pronto."
|
||||
},
|
||||
"wn8": {
|
||||
"$": "WN8",
|
||||
"very_bad": "Muy malo",
|
||||
"bad": "Malo",
|
||||
"below_average": "Inferior al promedio",
|
||||
"average": "Promedio",
|
||||
"above_average": "Superior al promedio",
|
||||
"good": "Bueno",
|
||||
"very_good": "Muy bueno",
|
||||
"great": "Genial",
|
||||
"unicum": "Unicum",
|
||||
"super_unicum": "Super unicum"
|
||||
},
|
||||
"subcommands": {
|
||||
"today": {
|
||||
"$": "hoy",
|
||||
"description": "Hoy"
|
||||
},
|
||||
"30": {
|
||||
"$": "30",
|
||||
"description": "30 días"
|
||||
},
|
||||
"60": {
|
||||
"$": "60",
|
||||
"description": "60 días"
|
||||
},
|
||||
"90": {
|
||||
"$": "90",
|
||||
"description": "90 días"
|
||||
},
|
||||
"career": {
|
||||
"$": "carrera",
|
||||
"description": "Carrera"
|
||||
},
|
||||
"custom": {
|
||||
"$": "personalizado",
|
||||
"description": "Rango personalizado",
|
||||
"options": {
|
||||
"start": {
|
||||
"$": "comienzo",
|
||||
"description": "Comenzar en cantidad de días pasados desde hoy"
|
||||
},
|
||||
"end": {
|
||||
"$": "fin",
|
||||
"description": "Terminar en cantidad de días pasados desde hoy"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"clan": {
|
||||
"$": "clan",
|
||||
"description": "El nombre o etiqueta del clan"
|
||||
},
|
||||
"tank": {
|
||||
"$": "tanque",
|
||||
"description": "El tanque al cual conseguirle estadísticas"
|
||||
},
|
||||
"username": {
|
||||
"$": "usuario",
|
||||
"description": "El nombre de usuario de Blitz"
|
||||
},
|
||||
"filters": {
|
||||
"nation": {
|
||||
"$": "nación",
|
||||
"description": "Nación"
|
||||
},
|
||||
"tank_class": {
|
||||
"$": "clase-de-tanque",
|
||||
"description": "Clase de tanque"
|
||||
},
|
||||
"tree_type": {
|
||||
"$": "tipo-de-árbol",
|
||||
"description": "Tipo de árbol"
|
||||
}
|
||||
},
|
||||
"region": {
|
||||
"$": "región",
|
||||
"description": "Región"
|
||||
},
|
||||
"tier": {
|
||||
"$": "nivel",
|
||||
"description": "Nivel",
|
||||
"choices": {
|
||||
"tier": "Nivel %s - %s"
|
||||
}
|
||||
}
|
||||
},
|
||||
"periods": {
|
||||
"career": "Carrera",
|
||||
"today": "Hoy",
|
||||
"days": "%s días",
|
||||
"custom": "%s - %s días"
|
||||
},
|
||||
"filters": {
|
||||
"none": "Sin filtros",
|
||||
"tier": "Nivel %s"
|
||||
},
|
||||
"no_data": {
|
||||
"battles_in_period": "No hay batallas jugadas en este período",
|
||||
"battles_in_season": "No hay batallas jugadas en esta temporada",
|
||||
"players_in_period": "No hay jugadores en este período",
|
||||
"tanks_found": "No se encontraron tanques"
|
||||
},
|
||||
"buttons": {
|
||||
"refresh": "Actualizar"
|
||||
},
|
||||
"hero_stats": {
|
||||
"battles": "Batallas",
|
||||
"winrate": "Tasa de victorias",
|
||||
"damage": "Daño",
|
||||
"damage_ratio": "Relación de daño",
|
||||
"tier": "Nivel",
|
||||
"survival": "Supervivencia",
|
||||
"accuracy": "Precisión",
|
||||
"kills": "Bajas"
|
||||
}
|
||||
},
|
||||
"commands": {
|
||||
"auction": {
|
||||
"$": "auction",
|
||||
"description": "Tanks available right now in the auction",
|
||||
"body": {
|
||||
"title": "Blitz Auction",
|
||||
"subtitle": "%s available • next prices %s\nBid now: %s",
|
||||
"next": "Next price: %s",
|
||||
"available": "Available: %s / %s"
|
||||
},
|
||||
"errors": {
|
||||
"no_auction": "# No ongoing auction\n\nCurrently, there are no tanks available for purchase in the auction. If you think this is an error, please report this discrepancy in [the official Discord Server](https://discord.gg/nDt7AjGJQH)."
|
||||
},
|
||||
"actions": {
|
||||
"bid": "Bid now"
|
||||
}
|
||||
},
|
||||
"replay": {
|
||||
"$": "replay",
|
||||
"description": "Display replay results"
|
||||
},
|
||||
"research": {
|
||||
"$": "investigar",
|
||||
"description": "Enumera los gastos por investigar una línea",
|
||||
"options": {
|
||||
"target_tank": {
|
||||
"$": "tanque-objetivo",
|
||||
"description": "El último tanque a investigar en la línea"
|
||||
},
|
||||
"starting_tank": {
|
||||
"$": "tanque-inicial",
|
||||
"description": "El tanque inicial en la línea (se deduce automáticamente si no se proporciona)"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"subtitle": "Investigar",
|
||||
"total": "Total",
|
||||
"research": "Investigar: %s",
|
||||
"upgrades": "Mejoras: %s",
|
||||
"purchase": "Comprar: %s",
|
||||
"equipment": "Equipamiento: %s",
|
||||
"estimation": "# ¡Esto es una estimación!\n\nEsta lista podría incluir tanques ya investigados debido a la información errónea que proporciona Wargaming. Si puedes, prueba proporcionando un `tanque-inicial` de la línea al usar el comando."
|
||||
},
|
||||
"errors": {
|
||||
"non_tech_tree": "# %s no está en el árbol tecnológico\n\nNo puedes investigar un tanque prémium o coleccionista.",
|
||||
"tier_1": "# %s es un nivel I\n\nLos tanque de nivel I están siempre desbloqueados gratuitamente para todos los jugadores.",
|
||||
"already_researched": "# %s ya está investigado\n\nPrueba proporcionando un `tanque-inicial` al usar el comando para ver los totales para una línea que ya has investigado.",
|
||||
"start_end_equal": "# %s fue proporcionado dos veces\n\nAsegúrate de que `tanque-inicial` y `tanque-objetivo` son diferentes.",
|
||||
"tanks_not_on_line": "# %s y %s no están en la misma línea\n\nAsegúrate de que `tanque-inicial` y `tanque-objetivo` están en la misma línea del árbol tecnológico.",
|
||||
"unordered": "# %s de nivel superior a %s\n\nAsegúrate de proporcionar %s como el `tanque-inicial` en su lugar ya que es el tanque de nivel inferior."
|
||||
}
|
||||
},
|
||||
"about": {
|
||||
"$": "sobre",
|
||||
"description": "Toda la información que necesitas sobre el bot",
|
||||
"subcommands": {
|
||||
"commands": {
|
||||
"$": "comandos",
|
||||
"description": "Lista de todos los comandos y sus descripciones",
|
||||
"body": "# Comandos\n\nBlitzkrieg ofrece los siguientes comandos:\n\n"
|
||||
},
|
||||
"embeds": {
|
||||
"$": "embeds",
|
||||
"description": "Cómo funcionan los embeds"
|
||||
},
|
||||
"introduction": {
|
||||
"$": "introducción",
|
||||
"description": "Sobre el bot"
|
||||
},
|
||||
"invite": {
|
||||
"$": "invitar",
|
||||
"description": "Cómo invitar al bot"
|
||||
},
|
||||
"timezones": {
|
||||
"$": "zonas-horarias",
|
||||
"description": "Cómo Blitzkrieg infiere y utiliza tu zona horaria"
|
||||
},
|
||||
"credits": {
|
||||
"$": "credits",
|
||||
"description": "People who have helped BlitzKit"
|
||||
}
|
||||
}
|
||||
},
|
||||
"breakdown": {
|
||||
"$": "resumen",
|
||||
"description": "Resumen de un período por tanques jugados",
|
||||
"body": {
|
||||
"total": "Total",
|
||||
"battles": "Batallas",
|
||||
"wn8": "WN8",
|
||||
"winrate": "Tasa de victorias",
|
||||
"damage": "Daño",
|
||||
"unknown_tank": "Tanque desconocido %s"
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"$": "depurar",
|
||||
"description": "Muestra más información sobre el bot",
|
||||
"body": {
|
||||
"title": "# Depuración\n\n",
|
||||
"version": "Versión",
|
||||
"shard": {
|
||||
"$": "Partición",
|
||||
"default": "predeterminado"
|
||||
},
|
||||
"uptime": "Tiempo en línea"
|
||||
}
|
||||
},
|
||||
"evolution": {
|
||||
"$": "evolución",
|
||||
"description": "Evolución de estadísticas",
|
||||
"groups": {
|
||||
"player": {
|
||||
"$": "jugador",
|
||||
"description": "Estadísticas del jugador"
|
||||
},
|
||||
"tank": {
|
||||
"$": "tanque",
|
||||
"description": "Estadísticas del tanque"
|
||||
}
|
||||
}
|
||||
},
|
||||
"inactive": {
|
||||
"$": "inactivo",
|
||||
"description": "Enumera a todos los jugadores inactivos en un clan por encima de un umbral",
|
||||
"options": {
|
||||
"threshold": {
|
||||
"$": "umbral",
|
||||
"description": "El número de días inactivo (predeterminado: %s días)"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"subtitle": "Inactivo por %s+ días",
|
||||
"listing": "%s días"
|
||||
}
|
||||
},
|
||||
"full_stats": {
|
||||
"$": "estadísticas-completas",
|
||||
"description": "Estadísticas completas del juego",
|
||||
"body": {
|
||||
"cards": {
|
||||
"games": {
|
||||
"$": "Partidas",
|
||||
"winrate": "Tasa de victorias",
|
||||
"battles": "Batallas",
|
||||
"wins_losses": "Victorias / derrotas"
|
||||
},
|
||||
"efficiency": {
|
||||
"$": "Eficiencia",
|
||||
"wn8": "WN8",
|
||||
"survival": "Supervivencia",
|
||||
"accuracy": "Precisión"
|
||||
},
|
||||
"lethality": {
|
||||
"$": "Letalidad",
|
||||
"average_damage": "Daño promedio",
|
||||
"damage_per_tier": "Daño por nivel",
|
||||
"damage_ratio": "Relación de daño",
|
||||
"average_kills": "Promedio de bajas"
|
||||
},
|
||||
"miscellaneous": {
|
||||
"$": "Misceláneo",
|
||||
"average_tier": "Nivel promedio",
|
||||
"average_spots": "Promedio de detecciones",
|
||||
"average_xp": "Promedio de XP",
|
||||
"kills_to_death_ratio": "Relación bajas-muertes"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"link": {
|
||||
"$": "vincular",
|
||||
"description": "Vincula tu cuenta de Blitz y Discord",
|
||||
"body": {
|
||||
"accounts_linked": "Cuentas vinculadas",
|
||||
"no_role_permissions": {
|
||||
"$": "%s no se pudo verificar",
|
||||
"description": "No tengo permiso para administrar roles."
|
||||
}
|
||||
},
|
||||
"embed": {
|
||||
"title": "¿Cuenta incorrecta?",
|
||||
"description": "Usa el comando de nuevo y selecciona un usuario de los resultados de búsqueda."
|
||||
}
|
||||
},
|
||||
"search_clans": {
|
||||
"$": "buscar-clanes",
|
||||
"description": "Buscar clanes",
|
||||
"options": {
|
||||
"limit": {
|
||||
"$": "límite",
|
||||
"description": "El número máximo de resultados de clanes (predeterminado: %s)"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"title": "Búsqueda del clan %s en la región %s",
|
||||
"no_results": "No se encontraron clanes"
|
||||
}
|
||||
},
|
||||
"search_players": {
|
||||
"$": "buscar-jugadores",
|
||||
"description": "Buscar jugadores",
|
||||
"options": {
|
||||
"limit": {
|
||||
"$": "límite",
|
||||
"description": "El número máximo para resultados de jugador (predeterminado: %s)"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"title": "Búsqueda del jugador %s en la región %s",
|
||||
"no_results": "No se encontraron jugadores"
|
||||
}
|
||||
},
|
||||
"rating_leaderboard": {
|
||||
"$": "rating-leaderboard",
|
||||
"description": "Rating battles statistics",
|
||||
"subcommands": {
|
||||
"neighbors": {
|
||||
"$": "vecinos",
|
||||
"description": "Neighboring players on the leaderboard"
|
||||
},
|
||||
"league": {
|
||||
"$": "liga",
|
||||
"description": "Mejores jugadores de una liga"
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"limit": {
|
||||
"$": "límite",
|
||||
"description": "Cuántos vecinos a mostrar (predeterminado: %s)"
|
||||
},
|
||||
"season": {
|
||||
"$": "temporada",
|
||||
"description": "Número de temporada (predeterminado: actual)",
|
||||
"choices": {
|
||||
"current": "%s (actual)"
|
||||
}
|
||||
},
|
||||
"league": {
|
||||
"$": "liga",
|
||||
"description": "La liga a mostrar"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"top_players": "Mejores %s jugadores",
|
||||
"no_participation": "# %s didn't play rating in season %s\n\nThis player did not participate in this season or did not get past calibration.",
|
||||
"no_ongoing_season": "# No ongoing season\n\nThere isn't a currently running rating season.",
|
||||
"deleted_player": "%s eliminado",
|
||||
"neighbors": "Rating neighbors",
|
||||
"more": "+ %s más"
|
||||
}
|
||||
},
|
||||
"today": {
|
||||
"$": "hoy",
|
||||
"description": "Tanques jugados hoy y estadísticas"
|
||||
},
|
||||
"stats": {
|
||||
"$": "estadísticas",
|
||||
"description": "Estadísticas rápidas para un período"
|
||||
},
|
||||
"owned_tanks": {
|
||||
"$": "tanques-propios",
|
||||
"description": "Muestra todos los tanques propios en un nivel",
|
||||
"body": {
|
||||
"title": "# Tanques de %s de nivel %s\n\n"
|
||||
}
|
||||
},
|
||||
"permissions": {
|
||||
"$": "permisos",
|
||||
"description": "Comprueba si el bot tiene los permisos requeridos para funcionar",
|
||||
"body": {
|
||||
"title": "# Permisos\n\n%s",
|
||||
"view_channels": "Ver canales: necesario para encontrar el mensaje en el cual el botón \"actualizar\" fue usado",
|
||||
"read_message_history": "Leer historial de mensajes: necesario para encontrar el mensaje a actualizar",
|
||||
"attach_files": "Adjuntar archivos: necesario para añadir imágenes a los comandos basados en estas",
|
||||
"external_emojis": "Emoticonos externos: necesario para añadir emoticonos de banderas nacionales y clases de tanque"
|
||||
}
|
||||
},
|
||||
"ping": {
|
||||
"$": "ping",
|
||||
"description": "Comprueba si el bot está vivo.",
|
||||
"body": {
|
||||
"pong": "Pong 🏓",
|
||||
"pong_with_time": "Pong 🏓 - %sms"
|
||||
},
|
||||
"subcommands": {
|
||||
"blitzkit": {
|
||||
"$": "blitzkit",
|
||||
"description": "Ping BlitzKit"
|
||||
},
|
||||
"wotb": {
|
||||
"$": "wotb",
|
||||
"description": "Hacerle un ping a World of Tanks Blitz"
|
||||
}
|
||||
}
|
||||
},
|
||||
"player_info": {
|
||||
"$": "info-jugador",
|
||||
"description": "Información básica sobre un jugador",
|
||||
"body": {
|
||||
"title": "Información de %s",
|
||||
"nickname": "Apodo",
|
||||
"battles": "Batallas",
|
||||
"winrate": "Tasa de victorias",
|
||||
"account_id": "ID de cuenta",
|
||||
"created": "Creado",
|
||||
"last_battle": "Última batalla"
|
||||
}
|
||||
},
|
||||
"rating": {
|
||||
"$": "rating-session",
|
||||
"description": "Rating player's statistics",
|
||||
"subcommands": {
|
||||
"today": {
|
||||
"$": "today",
|
||||
"description": "Today's rating statistics"
|
||||
},
|
||||
"season": {
|
||||
"$": "season",
|
||||
"description": "This season's rating statistics"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"subtitle": {
|
||||
"today": "Today's rating statistics",
|
||||
"season": "This season's rating statistics"
|
||||
}
|
||||
},
|
||||
"errors": {
|
||||
"no_participation": "# %s hasn't played rating\n\nThis player hasn't participated in the rating gamemode this season.",
|
||||
"unrecorded_stats": "# Estadísticas no disponibles actualmente\n\nWargaming podría estar sufriendo una caída del servidor. Si hay alguna temporada en curso, las estadísticas deberían estar disponibles en 24 horas."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"website": {}
|
||||
}
|
||||
@@ -1,601 +0,0 @@
|
||||
{
|
||||
"common": {
|
||||
"wn8_percentile": {
|
||||
"0": "Jako loše",
|
||||
"1": "Loše",
|
||||
"2": "Ispod prosečnog",
|
||||
"3": "Prosečno",
|
||||
"4": "Nad prosečno",
|
||||
"5": "Dobro",
|
||||
"6": "Jako dobro",
|
||||
"7": "Super",
|
||||
"8": "Legendarno",
|
||||
"9": "Super Legendarno"
|
||||
},
|
||||
"bkni_percentile": {
|
||||
"0": "Super malum",
|
||||
"1": "Malum",
|
||||
"2": "Very bad",
|
||||
"3": "Bad",
|
||||
"4": "Below average",
|
||||
"5": "Average",
|
||||
"6": "Above average",
|
||||
"7": "Good",
|
||||
"8": "Very good",
|
||||
"9": "Unicum",
|
||||
"10": "Super unicum"
|
||||
},
|
||||
"nations": {
|
||||
"ussr": "S.S.S.R.",
|
||||
"germany": "Nemačka",
|
||||
"usa": "S.A.D.",
|
||||
"china": "Kina",
|
||||
"uk": "Vel. Brit.",
|
||||
"france": "Francuska",
|
||||
"japan": "Japan",
|
||||
"european": "Evropska Unija",
|
||||
"other": "Hibridna nacija"
|
||||
},
|
||||
"nations_adjectives": {
|
||||
"ussr": "U.S.S.R.",
|
||||
"germany": "German",
|
||||
"usa": "U.S.A.",
|
||||
"china": "Chinese",
|
||||
"uk": "U.K.",
|
||||
"france": "French",
|
||||
"japan": "Japanese",
|
||||
"european": "European",
|
||||
"other": "Hybrid"
|
||||
},
|
||||
"tank_class_short": {
|
||||
"-1": "unrecognized",
|
||||
"0": "Light",
|
||||
"1": "Medium",
|
||||
"2": "Heavy",
|
||||
"3": "TD"
|
||||
},
|
||||
"tank_class_short_plural_lowercase": {
|
||||
"0": "lights",
|
||||
"1": "mediums",
|
||||
"2": "heavies",
|
||||
"3": "TDs"
|
||||
},
|
||||
"tank_class_medium": {
|
||||
"-1": "unrecognized",
|
||||
"0": "Light",
|
||||
"1": "Medium",
|
||||
"2": "Heavy",
|
||||
"3": "Tank destroyer"
|
||||
},
|
||||
"tree_type": {
|
||||
"-1": "unrecognized",
|
||||
"0": "Tech tree",
|
||||
"1": "Premium",
|
||||
"2": "Collector"
|
||||
},
|
||||
"regions": {
|
||||
"normal": {
|
||||
"com": "Severna Amerika",
|
||||
"eu": "Evropa",
|
||||
"asia": "Azija-Pasifik"
|
||||
},
|
||||
"short": {
|
||||
"com": "NA",
|
||||
"eu": "EU",
|
||||
"asia": "APAC"
|
||||
}
|
||||
},
|
||||
"leagues": {
|
||||
"diamond": "Dijamant",
|
||||
"platinum": "Platina",
|
||||
"gold": "Zlato",
|
||||
"silver": "Srebro",
|
||||
"bronze": "Bronza"
|
||||
},
|
||||
"composite_stats": {
|
||||
"normalized_damage_dealt": "Damage",
|
||||
"normalized_damage_received": "Damage received",
|
||||
"normalized_deaths": "Deathrate",
|
||||
"normalized_frags": "Kills",
|
||||
"normalized_hits": "Hits",
|
||||
"normalized_losses": "Lossrate",
|
||||
"normalized_misses": "Misses",
|
||||
"normalized_shots": "Shots",
|
||||
"normalized_spotted": "Spots",
|
||||
"normalized_survived_battles": "Survival rate",
|
||||
"normalized_win_and_survived": "Winning and surviving rate",
|
||||
"normalized_wins": "Winrate",
|
||||
"normalized_xp": "XP",
|
||||
"normalized_battle_life_time": "Battle time",
|
||||
"cumulative_accuracy": "Accuracy",
|
||||
"cumulative_battles": "Battles",
|
||||
"cumulative_capture_points": "Total capture points",
|
||||
"cumulative_damage_dealt": "Total damage",
|
||||
"cumulative_damage_ratio": "Damage ratio",
|
||||
"cumulative_damage_received": "Total damage received",
|
||||
"cumulative_deaths": "Total deaths",
|
||||
"cumulative_dropped_capture_points": "Total dropped capture points",
|
||||
"cumulative_frags": "Total kills",
|
||||
"cumulative_hits": "Total hits",
|
||||
"cumulative_inaccuracy": "Inaccuracy",
|
||||
"cumulative_kills_to_death_ratio": "Kills to death ratio",
|
||||
"cumulative_losses": "Losses",
|
||||
"cumulative_misses": "Total misses",
|
||||
"cumulative_shots": "Total shots",
|
||||
"cumulative_spotted": "Total spots",
|
||||
"cumulative_survived_battles": "Survived battles",
|
||||
"cumulative_win_and_survived": "Won and survived battles",
|
||||
"cumulative_wins": "Wins",
|
||||
"cumulative_xp": "Total XP",
|
||||
"cumulative_wn8": "WN8",
|
||||
"cumulative_battle_life_time": "Total battle time"
|
||||
}
|
||||
},
|
||||
"bot": {
|
||||
"common": {
|
||||
"errors": {
|
||||
"clan_not_found": "# Could not find clan\nCouldn't find \"%s\". Try selecting a clan from the search result.",
|
||||
"player_not_found": "# Could not find user\nI couldn't find user \"%s\". Try picking an user from the search result, typing in a valid username, or using the `/link` command.",
|
||||
"player_not_linked": "# I don't know who you are\nUse the `/link` command to get started.",
|
||||
"tank_name_not_found": "# Tank not found\nCould not find tank by the name \"%s\".",
|
||||
"tank_id_not_found": "# Tank not found\nCould not find tank by the ID \"%s\". Try typing the name of the tank instead of a number.",
|
||||
"no_tank_stats": "# No tank stats available\nThis player doesn't have any stats available. This may not be the player you are looking for.",
|
||||
"get_help": "Help Discord server",
|
||||
"uncaught_error": "# Blitzkrieg ran into an error!\nWe're so sorry about this. Feel free to [join the official Discord server](https://discord.gg/nDt7AjGJQH) to get help.",
|
||||
"preview": "# This command is in preview\n\nYou can only access this command in [the official Discord server](https://discord.gg/nDt7AjGJQH). The command will be generally available soon."
|
||||
},
|
||||
"wn8": {
|
||||
"$": "WN8",
|
||||
"very_bad": "Jako loše",
|
||||
"bad": "Loše",
|
||||
"below_average": "Ispod prosečnog",
|
||||
"average": "Prosečno",
|
||||
"above_average": "Nad prosečno",
|
||||
"good": "Dobro",
|
||||
"very_good": "Jako dobro",
|
||||
"great": "Super",
|
||||
"unicum": "Legendarno",
|
||||
"super_unicum": "Super Legendarno"
|
||||
},
|
||||
"subcommands": {
|
||||
"today": {
|
||||
"$": "danas",
|
||||
"description": "Danas"
|
||||
},
|
||||
"30": {
|
||||
"$": "30",
|
||||
"description": "30 dana"
|
||||
},
|
||||
"60": {
|
||||
"$": "60",
|
||||
"description": "60 dana"
|
||||
},
|
||||
"90": {
|
||||
"$": "90",
|
||||
"description": "90 dana"
|
||||
},
|
||||
"career": {
|
||||
"$": "karijera",
|
||||
"description": "Karijera"
|
||||
},
|
||||
"custom": {
|
||||
"$": "proizvoljno",
|
||||
"description": "Proizvoljna daljina",
|
||||
"options": {
|
||||
"start": {
|
||||
"$": "kreni",
|
||||
"description": "Start in number of days ago from today"
|
||||
},
|
||||
"end": {
|
||||
"$": "kraj",
|
||||
"description": "End in number of days ago from today"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"clan": {
|
||||
"$": "klan",
|
||||
"description": "The clan name or tag"
|
||||
},
|
||||
"tank": {
|
||||
"$": "tank",
|
||||
"description": "The tank to get stats for"
|
||||
},
|
||||
"username": {
|
||||
"$": "username",
|
||||
"description": "The Blitz username of the player"
|
||||
},
|
||||
"filters": {
|
||||
"nation": {
|
||||
"$": "nation",
|
||||
"description": "Nation"
|
||||
},
|
||||
"tank_class": {
|
||||
"$": "tank-class",
|
||||
"description": "Tank class"
|
||||
},
|
||||
"tree_type": {
|
||||
"$": "tree-type",
|
||||
"description": "Tree type"
|
||||
}
|
||||
},
|
||||
"region": {
|
||||
"$": "region",
|
||||
"description": "Region"
|
||||
},
|
||||
"tier": {
|
||||
"$": "tier",
|
||||
"description": "Tier",
|
||||
"choices": {
|
||||
"tier": "Tier %s - %s"
|
||||
}
|
||||
}
|
||||
},
|
||||
"periods": {
|
||||
"career": "Career",
|
||||
"today": "Today",
|
||||
"days": "%s days",
|
||||
"custom": "%s - %s days"
|
||||
},
|
||||
"filters": {
|
||||
"none": "No filters",
|
||||
"tier": "Tier %s"
|
||||
},
|
||||
"no_data": {
|
||||
"battles_in_period": "No battles played in this period",
|
||||
"battles_in_season": "No battles played in this season",
|
||||
"players_in_period": "No players in this period",
|
||||
"tanks_found": "No tanks found"
|
||||
},
|
||||
"buttons": {
|
||||
"refresh": "Refresh"
|
||||
},
|
||||
"hero_stats": {
|
||||
"battles": "Battles",
|
||||
"winrate": "Winrate",
|
||||
"damage": "Damage",
|
||||
"damage_ratio": "Damage ratio",
|
||||
"tier": "Tier",
|
||||
"survival": "Survival",
|
||||
"accuracy": "Accuracy",
|
||||
"kills": "Kills"
|
||||
}
|
||||
},
|
||||
"commands": {
|
||||
"auction": {
|
||||
"$": "auction",
|
||||
"description": "Tanks available right now in the auction",
|
||||
"body": {
|
||||
"title": "Blitz Auction",
|
||||
"subtitle": "%s available • next prices %s\nBid now: %s",
|
||||
"next": "Next price: %s",
|
||||
"available": "Available: %s / %s"
|
||||
},
|
||||
"errors": {
|
||||
"no_auction": "# No ongoing auction\n\nCurrently, there are no tanks available for purchase in the auction. If you think this is an error, please report this discrepancy in [the official Discord Server](https://discord.gg/nDt7AjGJQH)."
|
||||
},
|
||||
"actions": {
|
||||
"bid": "Bid now"
|
||||
}
|
||||
},
|
||||
"replay": {
|
||||
"$": "replay",
|
||||
"description": "Display replay results"
|
||||
},
|
||||
"research": {
|
||||
"$": "research",
|
||||
"description": "Lists the expenses in researching a line",
|
||||
"options": {
|
||||
"target_tank": {
|
||||
"$": "target-tank",
|
||||
"description": "The final tank to research in the line"
|
||||
},
|
||||
"starting_tank": {
|
||||
"$": "starting-tank",
|
||||
"description": "The starting tank in the line (inferred automatically if not provided)"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"subtitle": "Research",
|
||||
"total": "Total",
|
||||
"research": "Research: %s",
|
||||
"upgrades": "Upgrades: %s",
|
||||
"purchase": "Purchase: %s",
|
||||
"equipment": "Equipment: %s",
|
||||
"estimation": "# This is an estimation!\n\nThis list may include already researched tanks because of the inaccurate information Wargaming provides. Try providing a `starting-tank` from the line when using the command if you can."
|
||||
},
|
||||
"errors": {
|
||||
"non_tech_tree": "# %s is not on the tech tree\n\nYou cannot research a premium/collector tank.",
|
||||
"tier_1": "# %s is a tier I\n\nTier I tanks are always unlocked for free for all players.",
|
||||
"already_researched": "# %s is already researched\n\nTry providing a `starting-tank` when using the command to view the totals for a line you have already researched.",
|
||||
"start_end_equal": "# %s was provided twice\n\nMake sure `starting-tank` and `target-tank` are different.",
|
||||
"tanks_not_on_line": "# %s and %s are not on the same line\n\nMake sure `starting-tank` and `target-tank` are on the same tech-tree line.",
|
||||
"unordered": "# %s higher tiered to %s\n\nMake sure to provide %s as the `starting-tank` instead as it is the lower tiered tank."
|
||||
}
|
||||
},
|
||||
"about": {
|
||||
"$": "about",
|
||||
"description": "All the info you need about the bot",
|
||||
"subcommands": {
|
||||
"commands": {
|
||||
"$": "commands",
|
||||
"description": "List of all commands and their descriptions",
|
||||
"body": "# Commands\n\nBlitzkrieg offers the following commands:\n\n"
|
||||
},
|
||||
"embeds": {
|
||||
"$": "embeds",
|
||||
"description": "Kako embed radi"
|
||||
},
|
||||
"introduction": {
|
||||
"$": "uvod",
|
||||
"description": "O bot-u"
|
||||
},
|
||||
"invite": {
|
||||
"$": "pozovi",
|
||||
"description": "Kako pozvati robota"
|
||||
},
|
||||
"timezones": {
|
||||
"$": "vremenske zone",
|
||||
"description": "Kako \"Blitzkrieg\" koristi podatke o tvojoj vremenskoj zoni"
|
||||
},
|
||||
"credits": {
|
||||
"$": "credits",
|
||||
"description": "People who have helped BlitzKit"
|
||||
}
|
||||
}
|
||||
},
|
||||
"breakdown": {
|
||||
"$": "analiza",
|
||||
"description": "A period's breakdown by tanks played",
|
||||
"body": {
|
||||
"total": "Total",
|
||||
"battles": "Borbe",
|
||||
"wn8": "WN8",
|
||||
"winrate": "Procenat pobede",
|
||||
"damage": "Šteta",
|
||||
"unknown_tank": "Ne poznat tenk %s"
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"$": "odklanjanje-grešaka",
|
||||
"description": "Debug information about the bot",
|
||||
"body": {
|
||||
"title": "# Debug\n\n",
|
||||
"version": "Version",
|
||||
"shard": {
|
||||
"$": "Shard",
|
||||
"default": "default"
|
||||
},
|
||||
"uptime": "Uptime"
|
||||
}
|
||||
},
|
||||
"evolution": {
|
||||
"$": "evolution",
|
||||
"description": "Evolution of statistics",
|
||||
"groups": {
|
||||
"player": {
|
||||
"$": "player",
|
||||
"description": "Player statistics"
|
||||
},
|
||||
"tank": {
|
||||
"$": "tank",
|
||||
"description": "Tank statistics"
|
||||
}
|
||||
}
|
||||
},
|
||||
"inactive": {
|
||||
"$": "inactive",
|
||||
"description": "Lists all inactive players in a clan above a threshold",
|
||||
"options": {
|
||||
"threshold": {
|
||||
"$": "threshold",
|
||||
"description": "The number of days inactive (default: %s days)"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"subtitle": "Inactive for %s+ days",
|
||||
"listing": "%s days"
|
||||
}
|
||||
},
|
||||
"full_stats": {
|
||||
"$": "full-stats",
|
||||
"description": "Full in-game statistics",
|
||||
"body": {
|
||||
"cards": {
|
||||
"games": {
|
||||
"$": "Games",
|
||||
"winrate": "Winrate",
|
||||
"battles": "Battles",
|
||||
"wins_losses": "Wins / losses"
|
||||
},
|
||||
"efficiency": {
|
||||
"$": "Efficiency",
|
||||
"wn8": "WN8",
|
||||
"survival": "Survival",
|
||||
"accuracy": "Accuracy"
|
||||
},
|
||||
"lethality": {
|
||||
"$": "Lethality",
|
||||
"average_damage": "Average damage",
|
||||
"damage_per_tier": "Damage per tier",
|
||||
"damage_ratio": "Damage ratio",
|
||||
"average_kills": "Average kills"
|
||||
},
|
||||
"miscellaneous": {
|
||||
"$": "Miscellaneous",
|
||||
"average_tier": "Average tier",
|
||||
"average_spots": "Average spots",
|
||||
"average_xp": "Average XP",
|
||||
"kills_to_death_ratio": "Kills to death ratio"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"link": {
|
||||
"$": "link",
|
||||
"description": "Links your Blitz and Discord account",
|
||||
"body": {
|
||||
"accounts_linked": "Accounts linked",
|
||||
"no_role_permissions": {
|
||||
"$": "%s failed to verify",
|
||||
"description": "I don't have the permission to manage roles."
|
||||
}
|
||||
},
|
||||
"embed": {
|
||||
"title": "Incorrect account?",
|
||||
"description": "Use the command again and select a username from the search results."
|
||||
}
|
||||
},
|
||||
"search_clans": {
|
||||
"$": "search-clans",
|
||||
"description": "Search clans",
|
||||
"options": {
|
||||
"limit": {
|
||||
"$": "limit",
|
||||
"description": "The max number of clan results (default: %s)"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"title": "Clan search for %s in region %s",
|
||||
"no_results": "No clans found"
|
||||
}
|
||||
},
|
||||
"search_players": {
|
||||
"$": "search-players",
|
||||
"description": "Search players",
|
||||
"options": {
|
||||
"limit": {
|
||||
"$": "limit",
|
||||
"description": "The max number of player results (default: %s)"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"title": "Player search for %s in region %s",
|
||||
"no_results": "No players found"
|
||||
}
|
||||
},
|
||||
"rating_leaderboard": {
|
||||
"$": "rating-leaderboard",
|
||||
"description": "Rating battles statistics",
|
||||
"subcommands": {
|
||||
"neighbors": {
|
||||
"$": "neighbors",
|
||||
"description": "Neighboring players on the leaderboard"
|
||||
},
|
||||
"league": {
|
||||
"$": "league",
|
||||
"description": "Top players of a league"
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"limit": {
|
||||
"$": "limit",
|
||||
"description": "How many neighbors to display (default: %s)"
|
||||
},
|
||||
"season": {
|
||||
"$": "season",
|
||||
"description": "Season number (default: current)",
|
||||
"choices": {
|
||||
"current": "%s (current)"
|
||||
}
|
||||
},
|
||||
"league": {
|
||||
"$": "league",
|
||||
"description": "The league to display"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"top_players": "Top %s players",
|
||||
"no_participation": "# %s didn't play rating in season %s\n\nThis player did not participate in this season or did not get past calibration.",
|
||||
"no_ongoing_season": "# No ongoing season\n\nThere isn't a currently running rating season.",
|
||||
"deleted_player": "Deleted %s",
|
||||
"neighbors": "Rating neighbors",
|
||||
"more": "+ %s more"
|
||||
}
|
||||
},
|
||||
"today": {
|
||||
"$": "today",
|
||||
"description": "Today's played tanks and statistics"
|
||||
},
|
||||
"stats": {
|
||||
"$": "stats",
|
||||
"description": "Quick statistics for a period"
|
||||
},
|
||||
"owned_tanks": {
|
||||
"$": "owned-tanks",
|
||||
"description": "Shows all own tanks in a tier",
|
||||
"body": {
|
||||
"title": "# %s's owned tier %s tanks\n\n"
|
||||
}
|
||||
},
|
||||
"permissions": {
|
||||
"$": "permissions",
|
||||
"description": "Checks wether the bot has the required permissions to function",
|
||||
"body": {
|
||||
"title": "# Permissions\n\n%s",
|
||||
"view_channels": "View channels: needed to find the message the refresh button was used on",
|
||||
"read_message_history": "Read message history: needed to find the message to refresh",
|
||||
"attach_files": "Attach files: needed to add images to image-based commands",
|
||||
"external_emojis": "External emojis: needed to add national flags and tank class emojis"
|
||||
}
|
||||
},
|
||||
"ping": {
|
||||
"$": "ping",
|
||||
"description": "Check wether the bot is alive.",
|
||||
"body": {
|
||||
"pong": "Pong 🏓",
|
||||
"pong_with_time": "Pong 🏓 - %sms"
|
||||
},
|
||||
"subcommands": {
|
||||
"blitzkit": {
|
||||
"$": "blitzkit",
|
||||
"description": "Ping BlitzKit"
|
||||
},
|
||||
"wotb": {
|
||||
"$": "wotb",
|
||||
"description": "Ping World of Tanks Blitz"
|
||||
}
|
||||
}
|
||||
},
|
||||
"player_info": {
|
||||
"$": "player-info",
|
||||
"description": "Basic information about a player",
|
||||
"body": {
|
||||
"title": "%s's information",
|
||||
"nickname": "Nickname",
|
||||
"battles": "Battles",
|
||||
"winrate": "Winrate",
|
||||
"account_id": "Account ID",
|
||||
"created": "Created",
|
||||
"last_battle": "Last battle"
|
||||
}
|
||||
},
|
||||
"rating": {
|
||||
"$": "rating-session",
|
||||
"description": "Rating player's statistics",
|
||||
"subcommands": {
|
||||
"today": {
|
||||
"$": "today",
|
||||
"description": "Today's rating statistics"
|
||||
},
|
||||
"season": {
|
||||
"$": "season",
|
||||
"description": "This season's rating statistics"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"subtitle": {
|
||||
"today": "Today's rating statistics",
|
||||
"season": "This season's rating statistics"
|
||||
}
|
||||
},
|
||||
"errors": {
|
||||
"no_participation": "# %s hasn't played rating\n\nThis player hasn't participated in the rating gamemode this season.",
|
||||
"unrecorded_stats": "# Statistics currently unavailable\n\nWargaming may be currently be facing server downtime. If there is an on-going season, statistics should be available withing 24 hours."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"website": {}
|
||||
}
|
||||
@@ -1,601 +0,0 @@
|
||||
{
|
||||
"common": {
|
||||
"wn8_percentile": {
|
||||
"0": "Very bad",
|
||||
"1": "Bad",
|
||||
"2": "Below average",
|
||||
"3": "Average",
|
||||
"4": "Above average",
|
||||
"5": "Good",
|
||||
"6": "Very good",
|
||||
"7": "Great",
|
||||
"8": "Unicum",
|
||||
"9": "Super unicum"
|
||||
},
|
||||
"bkni_percentile": {
|
||||
"0": "Super malum",
|
||||
"1": "Malum",
|
||||
"2": "Very bad",
|
||||
"3": "Bad",
|
||||
"4": "Below average",
|
||||
"5": "Average",
|
||||
"6": "Above average",
|
||||
"7": "Good",
|
||||
"8": "Very good",
|
||||
"9": "Unicum",
|
||||
"10": "Super unicum"
|
||||
},
|
||||
"nations": {
|
||||
"ussr": "U.S.S.R.",
|
||||
"germany": "Germany",
|
||||
"usa": "U.S.A.",
|
||||
"china": "China",
|
||||
"uk": "U.K.",
|
||||
"france": "France",
|
||||
"japan": "Japan",
|
||||
"european": "European Nation",
|
||||
"other": "Hybrid Nation"
|
||||
},
|
||||
"nations_adjectives": {
|
||||
"ussr": "U.S.S.R.",
|
||||
"germany": "German",
|
||||
"usa": "U.S.A.",
|
||||
"china": "Chinese",
|
||||
"uk": "U.K.",
|
||||
"france": "French",
|
||||
"japan": "Japanese",
|
||||
"european": "European",
|
||||
"other": "Hybrid"
|
||||
},
|
||||
"tank_class_short": {
|
||||
"-1": "unrecognized",
|
||||
"0": "Light",
|
||||
"1": "Medium",
|
||||
"2": "Heavy",
|
||||
"3": "TD"
|
||||
},
|
||||
"tank_class_short_plural_lowercase": {
|
||||
"0": "lights",
|
||||
"1": "mediums",
|
||||
"2": "heavies",
|
||||
"3": "TDs"
|
||||
},
|
||||
"tank_class_medium": {
|
||||
"-1": "unrecognized",
|
||||
"0": "Light",
|
||||
"1": "Medium",
|
||||
"2": "Heavy",
|
||||
"3": "Tank destroyer"
|
||||
},
|
||||
"tree_type": {
|
||||
"-1": "unrecognized",
|
||||
"0": "Tech tree",
|
||||
"1": "Premium",
|
||||
"2": "Collector"
|
||||
},
|
||||
"regions": {
|
||||
"normal": {
|
||||
"com": "North America",
|
||||
"eu": "Europe",
|
||||
"asia": "Asia-Pacific"
|
||||
},
|
||||
"short": {
|
||||
"com": "NA",
|
||||
"eu": "EU",
|
||||
"asia": "APAC"
|
||||
}
|
||||
},
|
||||
"leagues": {
|
||||
"diamond": "Diamond",
|
||||
"platinum": "Platinum",
|
||||
"gold": "Gold",
|
||||
"silver": "Silver",
|
||||
"bronze": "Bronze"
|
||||
},
|
||||
"composite_stats": {
|
||||
"normalized_damage_dealt": "Damage",
|
||||
"normalized_damage_received": "Damage received",
|
||||
"normalized_deaths": "Deathrate",
|
||||
"normalized_frags": "Kills",
|
||||
"normalized_hits": "Hits",
|
||||
"normalized_losses": "Lossrate",
|
||||
"normalized_misses": "Misses",
|
||||
"normalized_shots": "Shots",
|
||||
"normalized_spotted": "Spots",
|
||||
"normalized_survived_battles": "Survival rate",
|
||||
"normalized_win_and_survived": "Winning and surviving rate",
|
||||
"normalized_wins": "Winrate",
|
||||
"normalized_xp": "XP",
|
||||
"normalized_battle_life_time": "Battle time",
|
||||
"cumulative_accuracy": "Accuracy",
|
||||
"cumulative_battles": "Battles",
|
||||
"cumulative_capture_points": "Total capture points",
|
||||
"cumulative_damage_dealt": "Total damage",
|
||||
"cumulative_damage_ratio": "Damage ratio",
|
||||
"cumulative_damage_received": "Total damage received",
|
||||
"cumulative_deaths": "Total deaths",
|
||||
"cumulative_dropped_capture_points": "Total dropped capture points",
|
||||
"cumulative_frags": "Total kills",
|
||||
"cumulative_hits": "Total hits",
|
||||
"cumulative_inaccuracy": "Inaccuracy",
|
||||
"cumulative_kills_to_death_ratio": "Kills to death ratio",
|
||||
"cumulative_losses": "Losses",
|
||||
"cumulative_misses": "Total misses",
|
||||
"cumulative_shots": "Total shots",
|
||||
"cumulative_spotted": "Total spots",
|
||||
"cumulative_survived_battles": "Survived battles",
|
||||
"cumulative_win_and_survived": "Won and survived battles",
|
||||
"cumulative_wins": "Wins",
|
||||
"cumulative_xp": "Total XP",
|
||||
"cumulative_wn8": "WN8",
|
||||
"cumulative_battle_life_time": "Total battle time"
|
||||
}
|
||||
},
|
||||
"bot": {
|
||||
"common": {
|
||||
"errors": {
|
||||
"clan_not_found": "# Could not find clan\nCouldn't find \"%s\". Try selecting a clan from the search result.",
|
||||
"player_not_found": "# Could not find user\nI couldn't find user \"%s\". Try picking an user from the search result, typing in a valid username, or using the `/link` command.",
|
||||
"player_not_linked": "# Use `/link` to get started\nI don't know who you are but you can tell me today!",
|
||||
"tank_name_not_found": "# Tank not found\nCould not find tank by the name \"%s\".",
|
||||
"tank_id_not_found": "# Tank not found\nCould not find tank by the ID \"%s\". Try typing the name of the tank instead of a number.",
|
||||
"no_tank_stats": "# No tank stats available\nThis player doesn't have any stats available. This may not be the player you are looking for.",
|
||||
"get_help": "Help Discord server",
|
||||
"uncaught_error": "# BlitzKit ran into an error!\nWe're so sorry about this. Feel free to [join the official Discord server](https://discord.gg/nDt7AjGJQH) to get help.",
|
||||
"preview": "# This command is in preview\n\nYou can only access this command in [the official Discord server](https://discord.gg/nDt7AjGJQH). The command will be generally available soon."
|
||||
},
|
||||
"wn8": {
|
||||
"$": "WN8",
|
||||
"very_bad": "Very bad",
|
||||
"bad": "Bad",
|
||||
"below_average": "Below average",
|
||||
"average": "Average",
|
||||
"above_average": "Above average",
|
||||
"good": "Good",
|
||||
"very_good": "Very good",
|
||||
"great": "Great",
|
||||
"unicum": "Unicum",
|
||||
"super_unicum": "Super unicum"
|
||||
},
|
||||
"subcommands": {
|
||||
"today": {
|
||||
"$": "today",
|
||||
"description": "Today"
|
||||
},
|
||||
"30": {
|
||||
"$": "30",
|
||||
"description": "30 days"
|
||||
},
|
||||
"60": {
|
||||
"$": "60",
|
||||
"description": "60 days"
|
||||
},
|
||||
"90": {
|
||||
"$": "90",
|
||||
"description": "90 days"
|
||||
},
|
||||
"career": {
|
||||
"$": "career",
|
||||
"description": "Career"
|
||||
},
|
||||
"custom": {
|
||||
"$": "custom",
|
||||
"description": "Custom range",
|
||||
"options": {
|
||||
"start": {
|
||||
"$": "start",
|
||||
"description": "Start in number of days ago from today"
|
||||
},
|
||||
"end": {
|
||||
"$": "end",
|
||||
"description": "End in number of days ago from today"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"clan": {
|
||||
"$": "clan",
|
||||
"description": "The clan name or tag"
|
||||
},
|
||||
"tank": {
|
||||
"$": "tank",
|
||||
"description": "The tank to get stats for"
|
||||
},
|
||||
"username": {
|
||||
"$": "username",
|
||||
"description": "The Blitz username of the player"
|
||||
},
|
||||
"filters": {
|
||||
"nation": {
|
||||
"$": "nation",
|
||||
"description": "Nation"
|
||||
},
|
||||
"tank_class": {
|
||||
"$": "tank-class",
|
||||
"description": "Tank class"
|
||||
},
|
||||
"tree_type": {
|
||||
"$": "tree-type",
|
||||
"description": "Tree type"
|
||||
}
|
||||
},
|
||||
"region": {
|
||||
"$": "region",
|
||||
"description": "Region"
|
||||
},
|
||||
"tier": {
|
||||
"$": "tier",
|
||||
"description": "Tier",
|
||||
"choices": {
|
||||
"tier": "Tier %s - %s"
|
||||
}
|
||||
}
|
||||
},
|
||||
"periods": {
|
||||
"career": "Career",
|
||||
"today": "Today",
|
||||
"days": "%s days",
|
||||
"custom": "%s - %s days"
|
||||
},
|
||||
"filters": {
|
||||
"none": "No filters",
|
||||
"tier": "Tier %s"
|
||||
},
|
||||
"no_data": {
|
||||
"battles_in_period": "No battles played in this period",
|
||||
"battles_in_season": "No battles played in this season",
|
||||
"players_in_period": "No players in this period",
|
||||
"tanks_found": "No tanks found"
|
||||
},
|
||||
"buttons": {
|
||||
"refresh": "Refresh"
|
||||
},
|
||||
"hero_stats": {
|
||||
"battles": "Battles",
|
||||
"winrate": "Winrate",
|
||||
"damage": "Damage",
|
||||
"damage_ratio": "Damage ratio",
|
||||
"tier": "Tier",
|
||||
"survival": "Survival",
|
||||
"accuracy": "Accuracy",
|
||||
"kills": "Kills"
|
||||
}
|
||||
},
|
||||
"commands": {
|
||||
"auction": {
|
||||
"$": "auction",
|
||||
"description": "Tanks available right now in the auction",
|
||||
"body": {
|
||||
"title": "Blitz Auction",
|
||||
"subtitle": "%s available • next prices %s\nBid now: %s",
|
||||
"next": "Next price: %s",
|
||||
"available": "Available: %s / %s"
|
||||
},
|
||||
"errors": {
|
||||
"no_auction": "# No ongoing auction\n\nCurrently, there are no tanks available for purchase in the auction. If you think this is an error, please report this discrepancy in [the official Discord Server](https://discord.gg/nDt7AjGJQH)."
|
||||
},
|
||||
"actions": {
|
||||
"bid": "Bid now"
|
||||
}
|
||||
},
|
||||
"replay": {
|
||||
"$": "replay",
|
||||
"description": "Display replay results"
|
||||
},
|
||||
"research": {
|
||||
"$": "research",
|
||||
"description": "Lists the expenses in researching a line",
|
||||
"options": {
|
||||
"target_tank": {
|
||||
"$": "target-tank",
|
||||
"description": "The final tank to research in the line"
|
||||
},
|
||||
"starting_tank": {
|
||||
"$": "starting-tank",
|
||||
"description": "The starting tank in the line (inferred automatically if not provided)"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"subtitle": "Research",
|
||||
"total": "Total",
|
||||
"research": "Research: %s",
|
||||
"upgrades": "Upgrades: %s",
|
||||
"purchase": "Purchase: %s",
|
||||
"equipment": "Equipment: %s",
|
||||
"estimation": "# This is an estimation!\n\nThis list may include already researched tanks because of the inaccurate information Wargaming provides. Try providing a `starting-tank` from the line when using the command if you can."
|
||||
},
|
||||
"errors": {
|
||||
"non_tech_tree": "# %s is not on the tech tree\n\nYou cannot research a premium/collector tank.",
|
||||
"tier_1": "# %s is a tier I\n\nTier I tanks are always unlocked for free for all players.",
|
||||
"already_researched": "# %s is already researched\n\nTry providing a `starting-tank` when using the command to view the totals for a line you have already researched.",
|
||||
"start_end_equal": "# %s was provided twice\n\nMake sure `starting-tank` and `target-tank` are different.",
|
||||
"tanks_not_on_line": "# %s and %s are not on the same line\n\nMake sure `starting-tank` and `target-tank` are on the same tech-tree line.",
|
||||
"unordered": "# %s higher tiered to %s\n\nMake sure to provide %s as the `starting-tank` instead as it is the lower tiered tank."
|
||||
}
|
||||
},
|
||||
"about": {
|
||||
"$": "about",
|
||||
"description": "All the info you need about the bot",
|
||||
"subcommands": {
|
||||
"commands": {
|
||||
"$": "commands",
|
||||
"description": "List of all commands and their descriptions",
|
||||
"body": "# Commands\n\nBlitzKit offers the following commands:\n\n"
|
||||
},
|
||||
"embeds": {
|
||||
"$": "embeds",
|
||||
"description": "How embeds work"
|
||||
},
|
||||
"introduction": {
|
||||
"$": "introduction",
|
||||
"description": "About the bot"
|
||||
},
|
||||
"invite": {
|
||||
"$": "invite",
|
||||
"description": "How to invite the bot"
|
||||
},
|
||||
"timezones": {
|
||||
"$": "timezones",
|
||||
"description": "How BlitzKit infers and uses your timezone"
|
||||
},
|
||||
"credits": {
|
||||
"$": "credits",
|
||||
"description": "People who have helped BlitzKit"
|
||||
}
|
||||
}
|
||||
},
|
||||
"breakdown": {
|
||||
"$": "breakdown",
|
||||
"description": "A period's breakdown by tanks played",
|
||||
"body": {
|
||||
"total": "Total",
|
||||
"battles": "Battles",
|
||||
"wn8": "WN8",
|
||||
"winrate": "Winrate",
|
||||
"damage": "Damage",
|
||||
"unknown_tank": "Unknown tank %s"
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"$": "debug",
|
||||
"description": "Debug information about the bot",
|
||||
"body": {
|
||||
"title": "# Debug\n\n",
|
||||
"version": "Version",
|
||||
"shard": {
|
||||
"$": "Shard",
|
||||
"default": "default"
|
||||
},
|
||||
"uptime": "Uptime"
|
||||
}
|
||||
},
|
||||
"evolution": {
|
||||
"$": "evolution",
|
||||
"description": "Evolution of statistics",
|
||||
"groups": {
|
||||
"player": {
|
||||
"$": "player",
|
||||
"description": "Player statistics"
|
||||
},
|
||||
"tank": {
|
||||
"$": "tank",
|
||||
"description": "Tank statistics"
|
||||
}
|
||||
}
|
||||
},
|
||||
"inactive": {
|
||||
"$": "inactive",
|
||||
"description": "Lists all inactive players in a clan above a threshold",
|
||||
"options": {
|
||||
"threshold": {
|
||||
"$": "threshold",
|
||||
"description": "The number of days inactive (default: %s days)"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"subtitle": "Inactive for %s+ days",
|
||||
"listing": "%s days"
|
||||
}
|
||||
},
|
||||
"full_stats": {
|
||||
"$": "full-stats",
|
||||
"description": "Full in-game statistics",
|
||||
"body": {
|
||||
"cards": {
|
||||
"games": {
|
||||
"$": "Games",
|
||||
"winrate": "Winrate",
|
||||
"battles": "Battles",
|
||||
"wins_losses": "Wins / losses"
|
||||
},
|
||||
"efficiency": {
|
||||
"$": "Efficiency",
|
||||
"wn8": "WN8",
|
||||
"survival": "Survival",
|
||||
"accuracy": "Accuracy"
|
||||
},
|
||||
"lethality": {
|
||||
"$": "Lethality",
|
||||
"average_damage": "Average damage",
|
||||
"damage_per_tier": "Damage per tier",
|
||||
"damage_ratio": "Damage ratio",
|
||||
"average_kills": "Average kills"
|
||||
},
|
||||
"miscellaneous": {
|
||||
"$": "Miscellaneous",
|
||||
"average_tier": "Average tier",
|
||||
"average_spots": "Average spots",
|
||||
"average_xp": "Average XP",
|
||||
"kills_to_death_ratio": "Kills to death ratio"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"link": {
|
||||
"$": "link",
|
||||
"description": "Links your Blitz and Discord account",
|
||||
"body": {
|
||||
"accounts_linked": "Accounts linked",
|
||||
"no_role_permissions": {
|
||||
"$": "%s failed to verify",
|
||||
"description": "I don't have the permission to manage roles."
|
||||
}
|
||||
},
|
||||
"embed": {
|
||||
"title": "Incorrect account?",
|
||||
"description": "Use the command again and select a username from the search results."
|
||||
}
|
||||
},
|
||||
"search_clans": {
|
||||
"$": "search-clans",
|
||||
"description": "Search clans",
|
||||
"options": {
|
||||
"limit": {
|
||||
"$": "limit",
|
||||
"description": "The max number of clan results (default: %s)"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"title": "Clan search for %s in region %s",
|
||||
"no_results": "No clans found"
|
||||
}
|
||||
},
|
||||
"search_players": {
|
||||
"$": "search-players",
|
||||
"description": "Search players",
|
||||
"options": {
|
||||
"limit": {
|
||||
"$": "limit",
|
||||
"description": "The max number of player results (default: %s)"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"title": "Player search for %s in region %s",
|
||||
"no_results": "No players found"
|
||||
}
|
||||
},
|
||||
"rating_leaderboard": {
|
||||
"$": "rating-leaderboard",
|
||||
"description": "Rating battles statistics",
|
||||
"subcommands": {
|
||||
"neighbors": {
|
||||
"$": "neighbors",
|
||||
"description": "Neighboring players on the leaderboard"
|
||||
},
|
||||
"league": {
|
||||
"$": "league",
|
||||
"description": "Top players of a league"
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"limit": {
|
||||
"$": "limit",
|
||||
"description": "How many neighbors to display (default: %s)"
|
||||
},
|
||||
"season": {
|
||||
"$": "season",
|
||||
"description": "Season number (default: current)",
|
||||
"choices": {
|
||||
"current": "%s (current)"
|
||||
}
|
||||
},
|
||||
"league": {
|
||||
"$": "league",
|
||||
"description": "The league to display"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"top_players": "Top %s players",
|
||||
"no_participation": "# %s didn't play rating in season %s\n\nThis player did not participate in this season or did not get past calibration.",
|
||||
"no_ongoing_season": "# No ongoing season\n\nThere isn't a currently running rating season.",
|
||||
"deleted_player": "Deleted %s",
|
||||
"neighbors": "Rating neighbors",
|
||||
"more": "+ %s more"
|
||||
}
|
||||
},
|
||||
"today": {
|
||||
"$": "today",
|
||||
"description": "Today's played tanks and statistics"
|
||||
},
|
||||
"stats": {
|
||||
"$": "stats",
|
||||
"description": "Quick statistics for a period"
|
||||
},
|
||||
"owned_tanks": {
|
||||
"$": "owned-tanks",
|
||||
"description": "Shows all own tanks in a tier",
|
||||
"body": {
|
||||
"title": "# %s's owned tier %s tanks\n\n"
|
||||
}
|
||||
},
|
||||
"permissions": {
|
||||
"$": "permissions",
|
||||
"description": "Checks wether the bot has the required permissions to function",
|
||||
"body": {
|
||||
"title": "# Permissions\n\n%s",
|
||||
"view_channels": "View channels: needed to find the message the refresh button was used on",
|
||||
"read_message_history": "Read message history: needed to find the message to refresh",
|
||||
"attach_files": "Attach files: needed to add images to image-based commands",
|
||||
"external_emojis": "External emojis: needed to add national flags and tank class emojis"
|
||||
}
|
||||
},
|
||||
"ping": {
|
||||
"$": "ping",
|
||||
"description": "Check wether the bot is alive.",
|
||||
"body": {
|
||||
"pong": "Pong 🏓",
|
||||
"pong_with_time": "Pong 🏓 - %sms"
|
||||
},
|
||||
"subcommands": {
|
||||
"blitzkit": {
|
||||
"$": "blitzkit",
|
||||
"description": "Ping BlitzKit"
|
||||
},
|
||||
"wotb": {
|
||||
"$": "wotb",
|
||||
"description": "Ping World of Tanks Blitz"
|
||||
}
|
||||
}
|
||||
},
|
||||
"player_info": {
|
||||
"$": "player-info",
|
||||
"description": "Basic information about a player",
|
||||
"body": {
|
||||
"title": "%s's information",
|
||||
"nickname": "Nickname",
|
||||
"battles": "Battles",
|
||||
"winrate": "Winrate",
|
||||
"account_id": "Account ID",
|
||||
"created": "Created",
|
||||
"last_battle": "Last battle"
|
||||
}
|
||||
},
|
||||
"rating": {
|
||||
"$": "rating",
|
||||
"description": "Rating player's statistics",
|
||||
"subcommands": {
|
||||
"today": {
|
||||
"$": "today",
|
||||
"description": "Today's rating statistics"
|
||||
},
|
||||
"season": {
|
||||
"$": "season",
|
||||
"description": "This season's rating statistics"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"subtitle": {
|
||||
"today": "Today's rating statistics",
|
||||
"season": "This season's rating statistics"
|
||||
}
|
||||
},
|
||||
"errors": {
|
||||
"no_participation": "# %s hasn't played rating\n\nThis player hasn't participated in the rating gamemode this season.",
|
||||
"unrecorded_stats": "# Statistics currently unavailable\n\nWargaming may be currently be facing server downtime. If there is an on-going season, statistics should be available withing 24 hours."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"website": {}
|
||||
}
|
||||
@@ -1,601 +0,0 @@
|
||||
{
|
||||
"common": {
|
||||
"wn8_percentile": {
|
||||
"0": "Very bad",
|
||||
"1": "Bad",
|
||||
"2": "Below average",
|
||||
"3": "Average",
|
||||
"4": "Above average",
|
||||
"5": "Good",
|
||||
"6": "Very good",
|
||||
"7": "Great",
|
||||
"8": "Unicum",
|
||||
"9": "Super unicum"
|
||||
},
|
||||
"bkni_percentile": {
|
||||
"0": "Super malum",
|
||||
"1": "Malum",
|
||||
"2": "Very bad",
|
||||
"3": "Bad",
|
||||
"4": "Below average",
|
||||
"5": "Average",
|
||||
"6": "Above average",
|
||||
"7": "Good",
|
||||
"8": "Very good",
|
||||
"9": "Unicum",
|
||||
"10": "Super unicum"
|
||||
},
|
||||
"nations": {
|
||||
"ussr": "U.S.S.R.",
|
||||
"germany": "Germany",
|
||||
"usa": "U.S.A.",
|
||||
"china": "China",
|
||||
"uk": "U.K.",
|
||||
"france": "France",
|
||||
"japan": "Japan",
|
||||
"european": "European Nation",
|
||||
"other": "Hybrid Nation"
|
||||
},
|
||||
"nations_adjectives": {
|
||||
"ussr": "U.S.S.R.",
|
||||
"germany": "German",
|
||||
"usa": "U.S.A.",
|
||||
"china": "Chinese",
|
||||
"uk": "U.K.",
|
||||
"france": "French",
|
||||
"japan": "Japanese",
|
||||
"european": "European",
|
||||
"other": "Hybrid"
|
||||
},
|
||||
"tank_class_short": {
|
||||
"-1": "unrecognized",
|
||||
"0": "Light",
|
||||
"1": "Medium",
|
||||
"2": "Heavy",
|
||||
"3": "TD"
|
||||
},
|
||||
"tank_class_short_plural_lowercase": {
|
||||
"0": "lights",
|
||||
"1": "mediums",
|
||||
"2": "heavies",
|
||||
"3": "TDs"
|
||||
},
|
||||
"tank_class_medium": {
|
||||
"-1": "unrecognized",
|
||||
"0": "Light",
|
||||
"1": "Medium",
|
||||
"2": "Heavy",
|
||||
"3": "Tank destroyer"
|
||||
},
|
||||
"tree_type": {
|
||||
"-1": "unrecognized",
|
||||
"0": "Tech tree",
|
||||
"1": "Premium",
|
||||
"2": "Collector"
|
||||
},
|
||||
"regions": {
|
||||
"normal": {
|
||||
"com": "North America",
|
||||
"eu": "Europe",
|
||||
"asia": "Asia-Pacific"
|
||||
},
|
||||
"short": {
|
||||
"com": "NA",
|
||||
"eu": "EU",
|
||||
"asia": "APAC"
|
||||
}
|
||||
},
|
||||
"leagues": {
|
||||
"diamond": "Diamond",
|
||||
"platinum": "Platinum",
|
||||
"gold": "Gold",
|
||||
"silver": "Silver",
|
||||
"bronze": "Bronze"
|
||||
},
|
||||
"composite_stats": {
|
||||
"normalized_damage_dealt": "Damage",
|
||||
"normalized_damage_received": "Damage received",
|
||||
"normalized_deaths": "Deathrate",
|
||||
"normalized_frags": "Kills",
|
||||
"normalized_hits": "Hits",
|
||||
"normalized_losses": "Lossrate",
|
||||
"normalized_misses": "Misses",
|
||||
"normalized_shots": "Shots",
|
||||
"normalized_spotted": "Spots",
|
||||
"normalized_survived_battles": "Survival rate",
|
||||
"normalized_win_and_survived": "Winning and surviving rate",
|
||||
"normalized_wins": "Winrate",
|
||||
"normalized_xp": "XP",
|
||||
"normalized_battle_life_time": "Battle time",
|
||||
"cumulative_accuracy": "Accuracy",
|
||||
"cumulative_battles": "Battles",
|
||||
"cumulative_capture_points": "Total capture points",
|
||||
"cumulative_damage_dealt": "Total damage",
|
||||
"cumulative_damage_ratio": "Damage ratio",
|
||||
"cumulative_damage_received": "Total damage received",
|
||||
"cumulative_deaths": "Total deaths",
|
||||
"cumulative_dropped_capture_points": "Total dropped capture points",
|
||||
"cumulative_frags": "Total kills",
|
||||
"cumulative_hits": "Total hits",
|
||||
"cumulative_inaccuracy": "Inaccuracy",
|
||||
"cumulative_kills_to_death_ratio": "Kills to death ratio",
|
||||
"cumulative_losses": "Losses",
|
||||
"cumulative_misses": "Total misses",
|
||||
"cumulative_shots": "Total shots",
|
||||
"cumulative_spotted": "Total spots",
|
||||
"cumulative_survived_battles": "Survived battles",
|
||||
"cumulative_win_and_survived": "Won and survived battles",
|
||||
"cumulative_wins": "Wins",
|
||||
"cumulative_xp": "Total XP",
|
||||
"cumulative_wn8": "WN8",
|
||||
"cumulative_battle_life_time": "Total battle time"
|
||||
}
|
||||
},
|
||||
"bot": {
|
||||
"common": {
|
||||
"errors": {
|
||||
"clan_not_found": "# Could not find clan\nCouldn't find \"%s\". Try selecting a clan from the search result.",
|
||||
"player_not_found": "# Could not find user\nI couldn't find user \"%s\". Try picking an user from the search result, typing in a valid username, or using the `/link` command.",
|
||||
"player_not_linked": "# Use `/link` to get started\nI don't know who you are but you can tell me today!",
|
||||
"tank_name_not_found": "# Tank not found\nCould not find tank by the name \"%s\".",
|
||||
"tank_id_not_found": "# Tank not found\nCould not find tank by the ID \"%s\". Try typing the name of the tank instead of a number.",
|
||||
"no_tank_stats": "# No tank stats available\nThis player doesn't have any stats available. This may not be the player you are looking for.",
|
||||
"get_help": "Help Discord server",
|
||||
"uncaught_error": "# BlitzKit ran into an error!\nWe're so sorry about this. Feel free to [join the official Discord server](https://discord.gg/nDt7AjGJQH) to get help.",
|
||||
"preview": "# This command is in preview\n\nYou can only access this command in [the official Discord server](https://discord.gg/nDt7AjGJQH). The command will be generally available soon."
|
||||
},
|
||||
"wn8": {
|
||||
"$": "WN8",
|
||||
"very_bad": "Very bad",
|
||||
"bad": "Bad",
|
||||
"below_average": "Below average",
|
||||
"average": "Average",
|
||||
"above_average": "Above average",
|
||||
"good": "Good",
|
||||
"very_good": "Very good",
|
||||
"great": "Great",
|
||||
"unicum": "Unicum",
|
||||
"super_unicum": "Super unicum"
|
||||
},
|
||||
"subcommands": {
|
||||
"today": {
|
||||
"$": "today",
|
||||
"description": "Today"
|
||||
},
|
||||
"30": {
|
||||
"$": "30",
|
||||
"description": "30 days"
|
||||
},
|
||||
"60": {
|
||||
"$": "60",
|
||||
"description": "60 days"
|
||||
},
|
||||
"90": {
|
||||
"$": "90",
|
||||
"description": "90 days"
|
||||
},
|
||||
"career": {
|
||||
"$": "career",
|
||||
"description": "Career"
|
||||
},
|
||||
"custom": {
|
||||
"$": "custom",
|
||||
"description": "Custom range",
|
||||
"options": {
|
||||
"start": {
|
||||
"$": "start",
|
||||
"description": "Start in number of days ago from today"
|
||||
},
|
||||
"end": {
|
||||
"$": "end",
|
||||
"description": "End in number of days ago from today"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"clan": {
|
||||
"$": "clan",
|
||||
"description": "The clan name or tag"
|
||||
},
|
||||
"tank": {
|
||||
"$": "tank",
|
||||
"description": "The tank to get stats for"
|
||||
},
|
||||
"username": {
|
||||
"$": "username",
|
||||
"description": "The Blitz username of the player"
|
||||
},
|
||||
"filters": {
|
||||
"nation": {
|
||||
"$": "nation",
|
||||
"description": "Nation"
|
||||
},
|
||||
"tank_class": {
|
||||
"$": "tank-class",
|
||||
"description": "Tank class"
|
||||
},
|
||||
"tree_type": {
|
||||
"$": "tree-type",
|
||||
"description": "Tree type"
|
||||
}
|
||||
},
|
||||
"region": {
|
||||
"$": "region",
|
||||
"description": "Region"
|
||||
},
|
||||
"tier": {
|
||||
"$": "tier",
|
||||
"description": "Tier",
|
||||
"choices": {
|
||||
"tier": "Tier %s - %s"
|
||||
}
|
||||
}
|
||||
},
|
||||
"periods": {
|
||||
"career": "Career",
|
||||
"today": "Today",
|
||||
"days": "%s days",
|
||||
"custom": "%s - %s days"
|
||||
},
|
||||
"filters": {
|
||||
"none": "No filters",
|
||||
"tier": "Tier %s"
|
||||
},
|
||||
"no_data": {
|
||||
"battles_in_period": "No battles played in this period",
|
||||
"battles_in_season": "No battles played in this season",
|
||||
"players_in_period": "No players in this period",
|
||||
"tanks_found": "No tanks found"
|
||||
},
|
||||
"buttons": {
|
||||
"refresh": "Refresh"
|
||||
},
|
||||
"hero_stats": {
|
||||
"battles": "Battles",
|
||||
"winrate": "Winrate",
|
||||
"damage": "Damage",
|
||||
"damage_ratio": "Damage ratio",
|
||||
"tier": "Tier",
|
||||
"survival": "Survival",
|
||||
"accuracy": "Accuracy",
|
||||
"kills": "Kills"
|
||||
}
|
||||
},
|
||||
"commands": {
|
||||
"auction": {
|
||||
"$": "auction",
|
||||
"description": "Tanks available right now in the auction",
|
||||
"body": {
|
||||
"title": "Blitz Auction",
|
||||
"subtitle": "%s available • next prices %s\nBid now: %s",
|
||||
"next": "Next price: %s",
|
||||
"available": "Available: %s / %s"
|
||||
},
|
||||
"errors": {
|
||||
"no_auction": "# No ongoing auction\n\nCurrently, there are no tanks available for purchase in the auction. If you think this is an error, please report this discrepancy in [the official Discord Server](https://discord.gg/nDt7AjGJQH)."
|
||||
},
|
||||
"actions": {
|
||||
"bid": "Bid now"
|
||||
}
|
||||
},
|
||||
"replay": {
|
||||
"$": "replay",
|
||||
"description": "Display replay results"
|
||||
},
|
||||
"research": {
|
||||
"$": "research",
|
||||
"description": "Lists the expenses in researching a line",
|
||||
"options": {
|
||||
"target_tank": {
|
||||
"$": "target-tank",
|
||||
"description": "The final tank to research in the line"
|
||||
},
|
||||
"starting_tank": {
|
||||
"$": "starting-tank",
|
||||
"description": "The starting tank in the line (inferred automatically if not provided)"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"subtitle": "Research",
|
||||
"total": "Total",
|
||||
"research": "Research: %s",
|
||||
"upgrades": "Upgrades: %s",
|
||||
"purchase": "Purchase: %s",
|
||||
"equipment": "Equipment: %s",
|
||||
"estimation": "# This is an estimation!\n\nThis list may include already researched tanks because of the inaccurate information Wargaming provides. Try providing a `starting-tank` from the line when using the command if you can."
|
||||
},
|
||||
"errors": {
|
||||
"non_tech_tree": "# %s is not on the tech tree\n\nYou cannot research a premium/collector tank.",
|
||||
"tier_1": "# %s is a tier I\n\nTier I tanks are always unlocked for free for all players.",
|
||||
"already_researched": "# %s is already researched\n\nTry providing a `starting-tank` when using the command to view the totals for a line you have already researched.",
|
||||
"start_end_equal": "# %s was provided twice\n\nMake sure `starting-tank` and `target-tank` are different.",
|
||||
"tanks_not_on_line": "# %s and %s are not on the same line\n\nMake sure `starting-tank` and `target-tank` are on the same tech-tree line.",
|
||||
"unordered": "# %s higher tiered to %s\n\nMake sure to provide %s as the `starting-tank` instead as it is the lower tiered tank."
|
||||
}
|
||||
},
|
||||
"about": {
|
||||
"$": "about",
|
||||
"description": "All the info you need about the bot",
|
||||
"subcommands": {
|
||||
"commands": {
|
||||
"$": "commands",
|
||||
"description": "List of all commands and their descriptions",
|
||||
"body": "# Commands\n\nBlitzKit offers the following commands:\n\n"
|
||||
},
|
||||
"embeds": {
|
||||
"$": "embeds",
|
||||
"description": "How embeds work"
|
||||
},
|
||||
"introduction": {
|
||||
"$": "introduction",
|
||||
"description": "About the bot"
|
||||
},
|
||||
"invite": {
|
||||
"$": "invite",
|
||||
"description": "How to invite the bot"
|
||||
},
|
||||
"timezones": {
|
||||
"$": "timezones",
|
||||
"description": "How BlitzKit infers and uses your timezone"
|
||||
},
|
||||
"credits": {
|
||||
"$": "credits",
|
||||
"description": "People who have helped BlitzKit"
|
||||
}
|
||||
}
|
||||
},
|
||||
"breakdown": {
|
||||
"$": "breakdown",
|
||||
"description": "A period's breakdown by tanks played",
|
||||
"body": {
|
||||
"total": "Total",
|
||||
"battles": "Battles",
|
||||
"wn8": "WN8",
|
||||
"winrate": "Winrate",
|
||||
"damage": "Damage",
|
||||
"unknown_tank": "Unknown tank %s"
|
||||
}
|
||||
},
|
||||
"debug": {
|
||||
"$": "debug",
|
||||
"description": "Debug information about the bot",
|
||||
"body": {
|
||||
"title": "# Debug\n\n",
|
||||
"version": "Version",
|
||||
"shard": {
|
||||
"$": "Shard",
|
||||
"default": "default"
|
||||
},
|
||||
"uptime": "Uptime"
|
||||
}
|
||||
},
|
||||
"evolution": {
|
||||
"$": "evolution",
|
||||
"description": "Evolution of statistics",
|
||||
"groups": {
|
||||
"player": {
|
||||
"$": "player",
|
||||
"description": "Player statistics"
|
||||
},
|
||||
"tank": {
|
||||
"$": "tank",
|
||||
"description": "Tank statistics"
|
||||
}
|
||||
}
|
||||
},
|
||||
"inactive": {
|
||||
"$": "inactive",
|
||||
"description": "Lists all inactive players in a clan above a threshold",
|
||||
"options": {
|
||||
"threshold": {
|
||||
"$": "threshold",
|
||||
"description": "The number of days inactive (default: %s days)"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"subtitle": "Inactive for %s+ days",
|
||||
"listing": "%s days"
|
||||
}
|
||||
},
|
||||
"full_stats": {
|
||||
"$": "full-stats",
|
||||
"description": "Full in-game statistics",
|
||||
"body": {
|
||||
"cards": {
|
||||
"games": {
|
||||
"$": "Games",
|
||||
"winrate": "Winrate",
|
||||
"battles": "Battles",
|
||||
"wins_losses": "Wins / losses"
|
||||
},
|
||||
"efficiency": {
|
||||
"$": "Efficiency",
|
||||
"wn8": "WN8",
|
||||
"survival": "Survival",
|
||||
"accuracy": "Accuracy"
|
||||
},
|
||||
"lethality": {
|
||||
"$": "Lethality",
|
||||
"average_damage": "Average damage",
|
||||
"damage_per_tier": "Damage per tier",
|
||||
"damage_ratio": "Damage ratio",
|
||||
"average_kills": "Average kills"
|
||||
},
|
||||
"miscellaneous": {
|
||||
"$": "Miscellaneous",
|
||||
"average_tier": "Average tier",
|
||||
"average_spots": "Average spots",
|
||||
"average_xp": "Average XP",
|
||||
"kills_to_death_ratio": "Kills to death ratio"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"link": {
|
||||
"$": "link",
|
||||
"description": "Links your Blitz and Discord account",
|
||||
"body": {
|
||||
"accounts_linked": "Accounts linked",
|
||||
"no_role_permissions": {
|
||||
"$": "%s failed to verify",
|
||||
"description": "I don't have the permission to manage roles."
|
||||
}
|
||||
},
|
||||
"embed": {
|
||||
"title": "Incorrect account?",
|
||||
"description": "Use the command again and select a username from the search results."
|
||||
}
|
||||
},
|
||||
"search_clans": {
|
||||
"$": "search-clans",
|
||||
"description": "Search clans",
|
||||
"options": {
|
||||
"limit": {
|
||||
"$": "limit",
|
||||
"description": "The max number of clan results (default: %s)"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"title": "Clan search for %s in region %s",
|
||||
"no_results": "No clans found"
|
||||
}
|
||||
},
|
||||
"search_players": {
|
||||
"$": "search-players",
|
||||
"description": "Search players",
|
||||
"options": {
|
||||
"limit": {
|
||||
"$": "limit",
|
||||
"description": "The max number of player results (default: %s)"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"title": "Player search for %s in region %s",
|
||||
"no_results": "No players found"
|
||||
}
|
||||
},
|
||||
"rating_leaderboard": {
|
||||
"$": "rating-leaderboard",
|
||||
"description": "Rating battles statistics",
|
||||
"subcommands": {
|
||||
"neighbors": {
|
||||
"$": "neighbors",
|
||||
"description": "Neighboring players on the leaderboard"
|
||||
},
|
||||
"league": {
|
||||
"$": "league",
|
||||
"description": "Top players of a league"
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"limit": {
|
||||
"$": "limit",
|
||||
"description": "How many neighbors to display (default: %s)"
|
||||
},
|
||||
"season": {
|
||||
"$": "season",
|
||||
"description": "Season number (default: current)",
|
||||
"choices": {
|
||||
"current": "%s (current)"
|
||||
}
|
||||
},
|
||||
"league": {
|
||||
"$": "league",
|
||||
"description": "The league to display"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"top_players": "Top %s players",
|
||||
"no_participation": "# %s didn't play rating in season %s\n\nThis player did not participate in this season or did not get past calibration.",
|
||||
"no_ongoing_season": "# No ongoing season\n\nThere isn't a currently running rating season.",
|
||||
"deleted_player": "Deleted %s",
|
||||
"neighbors": "Rating neighbors",
|
||||
"more": "+ %s more"
|
||||
}
|
||||
},
|
||||
"today": {
|
||||
"$": "today",
|
||||
"description": "Today's played tanks and statistics"
|
||||
},
|
||||
"stats": {
|
||||
"$": "stats",
|
||||
"description": "Quick statistics for a period"
|
||||
},
|
||||
"owned_tanks": {
|
||||
"$": "owned-tanks",
|
||||
"description": "Shows all own tanks in a tier",
|
||||
"body": {
|
||||
"title": "# %s's owned tier %s tanks\n\n"
|
||||
}
|
||||
},
|
||||
"permissions": {
|
||||
"$": "permissions",
|
||||
"description": "Checks wether the bot has the required permissions to function",
|
||||
"body": {
|
||||
"title": "# Permissions\n\n%s",
|
||||
"view_channels": "View channels: needed to find the message the refresh button was used on",
|
||||
"read_message_history": "Read message history: needed to find the message to refresh",
|
||||
"attach_files": "Attach files: needed to add images to image-based commands",
|
||||
"external_emojis": "External emojis: needed to add national flags and tank class emojis"
|
||||
}
|
||||
},
|
||||
"ping": {
|
||||
"$": "ping",
|
||||
"description": "Check wether the bot is alive.",
|
||||
"body": {
|
||||
"pong": "Pong 🏓",
|
||||
"pong_with_time": "Pong 🏓 - %sms"
|
||||
},
|
||||
"subcommands": {
|
||||
"blitzkit": {
|
||||
"$": "blitzkit",
|
||||
"description": "Ping BlitzKit"
|
||||
},
|
||||
"wotb": {
|
||||
"$": "wotb",
|
||||
"description": "Ping World of Tanks Blitz"
|
||||
}
|
||||
}
|
||||
},
|
||||
"player_info": {
|
||||
"$": "player-info",
|
||||
"description": "Basic information about a player",
|
||||
"body": {
|
||||
"title": "%s's information",
|
||||
"nickname": "Nickname",
|
||||
"battles": "Battles",
|
||||
"winrate": "Winrate",
|
||||
"account_id": "Account ID",
|
||||
"created": "Created",
|
||||
"last_battle": "Last battle"
|
||||
}
|
||||
},
|
||||
"rating": {
|
||||
"$": "rating",
|
||||
"description": "Rating player's statistics",
|
||||
"subcommands": {
|
||||
"today": {
|
||||
"$": "today",
|
||||
"description": "Today's rating statistics"
|
||||
},
|
||||
"season": {
|
||||
"$": "season",
|
||||
"description": "This season's rating statistics"
|
||||
}
|
||||
},
|
||||
"body": {
|
||||
"subtitle": {
|
||||
"today": "Today's rating statistics",
|
||||
"season": "This season's rating statistics"
|
||||
}
|
||||
},
|
||||
"errors": {
|
||||
"no_participation": "# %s hasn't played rating\n\nThis player hasn't participated in the rating gamemode this season.",
|
||||
"unrecorded_stats": "# Statistics currently unavailable\n\nWargaming may be currently be facing server downtime. If there is an on-going season, statistics should be available withing 24 hours."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"website": {}
|
||||
}
|
||||
Loaded 100 of 521 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user