@zhin.js/plugin-rps 1.1.15 → 1.1.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,17 +1,17 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
2
  import { defineCommand } from 'zhin.js/command';
3
3
  import { messageFromCommandInput, normalizeRpsAction } from '@zhin.js/game-kit';
4
- import { RPS_HELP, runRpsCommand } from "../../../lib/rps-command.js";
4
+ import { getRpsHelp, runRpsCommand } from "../../../lib/rps-command.js";
5
5
  import { resolveGameServices } from "../../../lib/runtime-store.js";
6
6
  export default defineCommand({
7
7
  description: 'RPS',
8
8
  params: { action: { type: 'string', default: '' } },
9
- async execute({ params, input, use, owner }) {
9
+ async execute({ params, input, use, locale, formatCommand }) {
10
10
  const action = normalizeRpsAction(String(params.action ?? ''));
11
11
  if (!action || action === 'help')
12
- return RPS_HELP;
12
+ return getRpsHelp({ locale, formatCommand });
13
13
  const services = resolveGameServices({ use });
14
- const message = messageFromCommandInput(input);
14
+ const message = messageFromCommandInput(input, { locale, formatCommand });
15
15
  return runRpsCommand(services, message, action);
16
16
  },
17
17
  });
@@ -1,16 +1,16 @@
1
1
  import { defineCommand } from 'zhin.js/command';
2
2
  import { messageFromCommandInput, normalizeRpsAction } from '@zhin.js/game-kit';
3
- import { RPS_HELP, runRpsCommand } from '../../../src/rps-command.js';
3
+ import { getRpsHelp, runRpsCommand } from '../../../src/rps-command.js';
4
4
  import { resolveGameServices } from '../../../src/runtime-store.js';
5
5
 
6
6
  export default defineCommand({
7
7
  description: 'RPS',
8
8
  params: { action: { type: 'string', default: '' } },
9
- async execute({ params, input, use, owner }) {
9
+ async execute({ params, input, use, locale, formatCommand }) {
10
10
  const action = normalizeRpsAction(String(params.action ?? ''));
11
- if (!action || action === 'help') return RPS_HELP;
11
+ if (!action || action === 'help') return getRpsHelp({ locale, formatCommand });
12
12
  const services = resolveGameServices({ use });
13
- const message = messageFromCommandInput(input);
13
+ const message = messageFromCommandInput(input, { locale, formatCommand });
14
14
  return runRpsCommand(services, message, action);
15
15
  },
16
16
  });
package/lib/engine.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { type Locale } from 'zhin.js/i18n';
1
2
  export declare const RPS_PREFIX = "rps";
2
3
  export type RpsMove = 'rock' | 'paper' | 'scissors';
3
4
  export declare const MOVE_LABELS: Record<RpsMove, string>;
@@ -6,3 +7,4 @@ export declare function randomBotMove(): RpsMove;
6
7
  export declare function resolveRound(player: RpsMove, bot: RpsMove): 0 | 1 | 2;
7
8
  export declare function parseMove(raw: string): RpsMove | null;
8
9
  export declare const WIN_TARGET = 3;
10
+ export declare function moveLabel(move: RpsMove, locale?: Locale | null): string;
package/lib/engine.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { createMessages } from 'zhin.js/i18n';
1
2
  import { secureRandomItem } from '@zhin.js/game-kit';
2
3
  export const RPS_PREFIX = 'rps';
3
4
  export const MOVE_LABELS = {
@@ -36,4 +37,6 @@ export function parseMove(raw) {
36
37
  return map[t] ?? null;
37
38
  }
38
39
  export const WIN_TARGET = 3;
40
+ const moveMessages = createMessages({ rock: { 'zh-CN': '✊ 石头', en: '✊ Rock' }, paper: { 'zh-CN': '✋ 布', en: '✋ Paper' }, scissors: { 'zh-CN': '✌️ 剪刀', en: '✌️ Scissors' } });
41
+ export function moveLabel(move, locale) { return moveMessages(locale ?? undefined, move); }
39
42
  //# sourceMappingURL=engine.js.map
package/lib/engine.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"engine.js","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAErD,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,CAAC;AAIhC,MAAM,CAAC,MAAM,WAAW,GAA4B;IAClD,IAAI,EAAE,MAAM;IACZ,KAAK,EAAE,KAAK;IACZ,QAAQ,EAAE,OAAO;CAClB,CAAC;AAEF,MAAM,KAAK,GAA6B;IACtC,IAAI,EAAE,UAAU;IAChB,KAAK,EAAE,MAAM;IACb,QAAQ,EAAE,OAAO;CAClB,CAAC;AAEF,MAAM,UAAU,aAAa;IAC3B,MAAM,KAAK,GAAc,CAAC,MAAM,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IACvD,OAAO,gBAAgB,CAAC,KAAK,CAAC,CAAC;AACjC,CAAC;AAED,wBAAwB;AACxB,MAAM,UAAU,YAAY,CAAC,MAAe,EAAE,GAAY;IACxD,IAAI,MAAM,KAAK,GAAG;QAAE,OAAO,CAAC,CAAC;IAC7B,OAAO,KAAK,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,GAAW;IACnC,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACnC,MAAM,GAAG,GAA4B;QACnC,IAAI,EAAE,MAAM;QACZ,KAAK,EAAE,OAAO;QACd,QAAQ,EAAE,UAAU;QACpB,EAAE,EAAE,MAAM;QACV,CAAC,EAAE,OAAO;QACV,EAAE,EAAE,UAAU;QACd,CAAC,EAAE,MAAM;QACT,CAAC,EAAE,OAAO;QACV,CAAC,EAAE,UAAU;KACd,CAAC;IACF,OAAO,GAAG,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;AACxB,CAAC;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC"}
1
+ {"version":3,"file":"engine.js","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAe,MAAM,cAAc,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAErD,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,CAAC;AAIhC,MAAM,CAAC,MAAM,WAAW,GAA4B;IAClD,IAAI,EAAE,MAAM;IACZ,KAAK,EAAE,KAAK;IACZ,QAAQ,EAAE,OAAO;CAClB,CAAC;AAEF,MAAM,KAAK,GAA6B;IACtC,IAAI,EAAE,UAAU;IAChB,KAAK,EAAE,MAAM;IACb,QAAQ,EAAE,OAAO;CAClB,CAAC;AAEF,MAAM,UAAU,aAAa;IAC3B,MAAM,KAAK,GAAc,CAAC,MAAM,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IACvD,OAAO,gBAAgB,CAAC,KAAK,CAAC,CAAC;AACjC,CAAC;AAED,wBAAwB;AACxB,MAAM,UAAU,YAAY,CAAC,MAAe,EAAE,GAAY;IACxD,IAAI,MAAM,KAAK,GAAG;QAAE,OAAO,CAAC,CAAC;IAC7B,OAAO,KAAK,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,GAAW;IACnC,MAAM,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACnC,MAAM,GAAG,GAA4B;QACnC,IAAI,EAAE,MAAM;QACZ,KAAK,EAAE,OAAO;QACd,QAAQ,EAAE,UAAU;QACpB,EAAE,EAAE,MAAM;QACV,CAAC,EAAE,OAAO;QACV,EAAE,EAAE,UAAU;QACd,CAAC,EAAE,MAAM;QACT,CAAC,EAAE,OAAO;QACV,CAAC,EAAE,UAAU;KACd,CAAC;IACF,OAAO,GAAG,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;AACxB,CAAC;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC;AAE5B,MAAM,YAAY,GAAG,cAAc,CAAC,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,KAAK,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,SAAS,EAAE,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,EAAE,aAAa,EAAE,EAAE,CAAC,CAAC;AAC9K,MAAM,UAAU,SAAS,CAAC,IAAa,EAAE,MAAsB,IAAY,OAAO,YAAY,CAAC,MAAM,IAAI,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC"}
package/lib/game-flow.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { createMessages, resolveLocale } from 'zhin.js/i18n';
1
2
  import { RPS_PREFIX, WIN_TARGET, randomBotMove, resolveRound, } from './engine.js';
2
3
  import { buildRpsView } from './view.js';
3
4
  /**
@@ -11,24 +12,26 @@ function renderView(session, message, lastRound) {
11
12
  export async function startGame(services, message) {
12
13
  const ch = `${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`;
13
14
  const active = await services.getActiveByChannel(ch);
15
+ const locale = resolveLocale(active ? active.locale : message.locale);
14
16
  if (active) {
15
17
  if (active.player_id === message.$sender.id) {
16
- return '你已有进行中的猜拳,发送「猜拳 继续」刷新,或「猜拳 放弃」。';
18
+ return messages(locale, 'text1');
17
19
  }
18
- return `本频道 ${active.player_name} 正在猜拳对决中。`;
20
+ return messages(locale, 'text2', { p0: active.player_name });
19
21
  }
20
22
  const session = await services.createSession(message);
21
23
  return renderView(session, message);
22
24
  }
23
25
  export async function handleChoice(services, message, sessionId, choiceId) {
24
26
  const session = await services.getById(sessionId);
27
+ const locale = resolveLocale(session ? session.locale : message.locale);
25
28
  if (!session)
26
- return '对局不存在。';
29
+ return messages(locale, 'text3');
27
30
  if (session.status !== 'active' && choiceId !== 'restart') {
28
- return '对局已结束,请点击再来一局。';
31
+ return messages(locale, 'text4');
29
32
  }
30
33
  if (session.player_id !== message.$sender.id)
31
- return '这是别人的对局。';
34
+ return messages(locale, 'text5');
32
35
  if (choiceId === 'restart') {
33
36
  await services.updateSession(session.id, { status: 'aborted' });
34
37
  return (await startGame(services, message)) ?? null;
@@ -39,7 +42,7 @@ export async function handleChoice(services, message, sessionId, choiceId) {
39
42
  }
40
43
  const player = choiceId;
41
44
  if (!['rock', 'paper', 'scissors'].includes(player))
42
- return '无效出拳。';
45
+ return messages(locale, 'text6');
43
46
  const bot = randomBotMove();
44
47
  const result = resolveRound(player, bot);
45
48
  let playerWins = session.player_wins;
@@ -64,9 +67,19 @@ export async function handleChoice(services, message, sessionId, choiceId) {
64
67
  }
65
68
  export async function continueGame(services, message) {
66
69
  const session = await services.getActiveForUser(`${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`, message.$sender.id);
70
+ const locale = resolveLocale(session ? session.locale : message.locale);
67
71
  if (!session)
68
- return '你没有进行中的猜拳,发送「猜拳 开始」。';
72
+ return messages(locale, 'text7');
69
73
  return renderView(session, message);
70
74
  }
71
75
  export { RPS_PREFIX };
76
+ const messages = createMessages({
77
+ text1: { 'zh-CN': "你已有进行中的猜拳,请使用当前对局的操作入口。", en: "You already have an active game. Continue using its controls." },
78
+ text2: { 'zh-CN': "本频道 {p0} 正在猜拳对决中。", en: "{p0} is playing rock, paper, scissors in this channel." },
79
+ text3: { 'zh-CN': "对局不存在。", en: "This game no longer exists." },
80
+ text4: { 'zh-CN': "对局已结束,请点击再来一局。", en: "This game has ended. Choose Play again." },
81
+ text5: { 'zh-CN': "这是别人的对局。", en: "This game belongs to another player." },
82
+ text6: { 'zh-CN': "无效出拳。", en: "Invalid move." },
83
+ text7: { 'zh-CN': "你没有进行中的猜拳,请使用当前对局的操作入口。", en: "You have no active rock, paper, scissors game." },
84
+ });
72
85
  //# sourceMappingURL=game-flow.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"game-flow.js","sourceRoot":"","sources":["../src/game-flow.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"game-flow.js","sourceRoot":"","sources":["../src/game-flow.ts"],"names":[],"mappings":"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"}
package/lib/models.d.ts CHANGED
@@ -4,6 +4,7 @@ declare module '@zhin.js/core' {
4
4
  interface Models {
5
5
  rps_sessions: {
6
6
  id: string;
7
+ locale?: 'zh-CN' | 'en' | null;
7
8
  adapter: string;
8
9
  endpoint: string;
9
10
  channel_type: string;
@@ -22,5 +23,7 @@ declare module '@zhin.js/core' {
22
23
  }
23
24
  export type RpsSessionRow = Models['rps_sessions'];
24
25
  export declare function defineHostTables(db: {
25
- define: (name: string, definition: Record<string, unknown>) => void;
26
+ define: (name: string, definition: Record<string, unknown>, options?: {
27
+ readonly addColumns?: readonly string[];
28
+ }) => void;
26
29
  }): void;
package/lib/models.js CHANGED
@@ -1,6 +1,7 @@
1
1
  export function defineHostTables(db) {
2
2
  db.define('rps_sessions', {
3
3
  id: { type: 'text', primary: true },
4
+ locale: { type: 'text', nullable: true },
4
5
  adapter: { type: 'text', nullable: false },
5
6
  endpoint: { type: 'text', nullable: false },
6
7
  channel_type: { type: 'text', nullable: false },
@@ -14,6 +15,6 @@ export function defineHostTables(db) {
14
15
  status: { type: 'text', default: 'active' },
15
16
  updated_at: { type: 'bigint', default: 0 },
16
17
  created_at: { type: 'bigint', default: 0 },
17
- });
18
+ }, { addColumns: ['locale'] });
18
19
  }
19
20
  //# sourceMappingURL=models.js.map
package/lib/models.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"models.js","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"AA4BA,MAAM,UAAU,gBAAgB,CAC9B,EAA2E;IAE3E,EAAE,CAAC,MAAM,CAAC,cAAc,EAAE;QACxB,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;QACnC,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC1C,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC3C,YAAY,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC/C,UAAU,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC7C,WAAW,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC9C,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC5C,WAAW,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE;QAC1C,WAAW,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QAC5C,QAAQ,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QACzC,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QACtC,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE;QAC3C,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,EAAE;QAC1C,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,EAAE;KAC3C,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"models.js","sourceRoot":"","sources":["../src/models.ts"],"names":[],"mappings":"AA6BA,MAAM,UAAU,gBAAgB,CAC9B,EAAkI;IAElI,EAAE,CAAC,MAAM,CAAC,cAAc,EAAE;QACxB,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;QACnC,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE;QACxC,OAAO,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC1C,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC3C,YAAY,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC/C,UAAU,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC7C,WAAW,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC9C,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE;QAC5C,WAAW,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,EAAE,EAAE;QAC1C,WAAW,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QAC5C,QAAQ,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QACzC,KAAK,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE;QACtC,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE;QAC3C,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,EAAE;QAC1C,UAAU,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,EAAE;KAC3C,EAAE,EAAE,UAAU,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;AACjC,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import { type GameMessageLike, type GameReply } from '@zhin.js/game-kit';
2
2
  import type { SessionService } from './session-service.js';
3
+ export declare function getRpsHelp(message?: Pick<GameMessageLike, 'locale' | 'formatCommand'>): string;
3
4
  export declare const RPS_HELP: string;
4
5
  export declare function runRpsCommand(services: SessionService, message: GameMessageLike, action: string): Promise<GameReply>;
@@ -1,23 +1,21 @@
1
- import { channelKey, } from '@zhin.js/game-kit';
1
+ import { formatGameHelp, gameCommandFeedback, gameCommandHint, channelKey } from '@zhin.js/game-kit';
2
+ import { createMessages } from 'zhin.js/i18n';
2
3
  import { continueGame, handleChoice, startGame } from './game-flow.js';
3
- export const RPS_HELP = [
4
- '✊✋✌️ 猜拳对决(三局两胜)',
5
- '猜拳 / rps — 帮助',
6
- '猜拳 开始 — 新对局',
7
- '猜拳 继续 — 刷新界面',
8
- '猜拳 放弃 — 结束对局',
9
- ].join('\n');
4
+ export function getRpsHelp(message = {}) {
5
+ return formatGameHelp(message, { 'zh-CN': "✊✋✌️ 猜拳对决(三局两胜)", en: "✊✋✌️ Rock Paper Scissors (best of three)" }, 'rps', ['start', 'continue', 'quit'], { 'zh-CN': "点击按钮或回复选项数字出拳。", en: "Choose a button or reply with its option number." });
6
+ }
7
+ export const RPS_HELP = getRpsHelp();
10
8
  export async function runRpsCommand(services, message, action) {
11
9
  const ch = channelKey(message);
12
10
  const userId = message.$sender.id;
13
11
  if (!action || action === 'help') {
14
12
  const active = await services.getActiveByChannel(ch);
15
- const lines = [RPS_HELP, ''];
13
+ const lines = [getRpsHelp(message), ''];
16
14
  if (active) {
17
- lines.push(`进行中:${active.player_name} · ${active.player_wins}:${active.bot_wins}`);
15
+ lines.push(messages(active.locale ?? undefined, 'text1', { p0: active.player_name, p1: active.player_wins, p2: active.bot_wins }));
18
16
  }
19
17
  else {
20
- lines.push('暂无对局,发送「猜拳 开始」或从游戏大厅进入。');
18
+ lines.push(gameCommandFeedback(message, 'noGame'), gameCommandHint(message, 'rps'));
21
19
  }
22
20
  return lines.join('\n');
23
21
  }
@@ -28,9 +26,12 @@ export async function runRpsCommand(services, message, action) {
28
26
  if (action === 'quit') {
29
27
  const row = await services.getActiveForUser(ch, userId);
30
28
  if (!row)
31
- return '你没有进行中的猜拳。';
29
+ return gameCommandFeedback(message, 'noGame');
32
30
  return (await handleChoice(services, message, row.id, 'quit')) ?? '';
33
31
  }
34
- return `未知子命令:${action}\n\n${RPS_HELP}`;
32
+ return gameCommandFeedback(message, 'unknown', action) + '\n\n' + getRpsHelp(message);
35
33
  }
34
+ const messages = createMessages({
35
+ text1: { 'zh-CN': "进行中:{p0} · {p1}:{p2}", en: "Playing: {p0} · {p1}:{p2}" },
36
+ });
36
37
  //# sourceMappingURL=rps-command.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"rps-command.js","sourceRoot":"","sources":["../src/rps-command.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,GAGX,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAGvE,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,iBAAiB;IACjB,eAAe;IACf,aAAa;IACb,cAAc;IACd,cAAc;CACf,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAEb,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,QAAwB,EACxB,OAAwB,EACxB,MAAc;IAEd,MAAM,EAAE,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;IAC/B,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;IAElC,IAAI,CAAC,MAAM,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC;QACrD,MAAM,KAAK,GAAG,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QAC7B,IAAI,MAAM,EAAE,CAAC;YACX,KAAK,CAAC,IAAI,CAAC,OAAO,MAAM,CAAC,WAAW,MAAM,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;QACrF,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,CAAC,yBAAyB,CAAC,CAAC;QACxC,CAAC;QACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED,IAAI,MAAM,KAAK,OAAO;QAAE,OAAO,CAAC,MAAM,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;IAC1E,IAAI,MAAM,KAAK,UAAU;QAAE,OAAO,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAElE,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACtB,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,gBAAgB,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QACxD,IAAI,CAAC,GAAG;YAAE,OAAO,YAAY,CAAC;QAC9B,OAAO,CAAC,MAAM,YAAY,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;IACvE,CAAC;IAED,OAAO,SAAS,MAAM,OAAO,QAAQ,EAAE,CAAC;AAC1C,CAAC"}
1
+ {"version":3,"file":"rps-command.js","sourceRoot":"","sources":["../src/rps-command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,eAAe,EAAE,UAAU,EAAwC,MAAM,mBAAmB,CAAC;AAC3I,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAGvE,MAAM,UAAU,UAAU,CAAC,UAA6D,EAAE;IACxF,OAAO,cAAc,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,iBAAiB,EAAE,EAAE,EAAE,0CAA0C,EAAE,EAAE,KAAK,EAAE,CAAC,OAAO,EAAE,UAAU,EAAE,MAAM,CAAC,EACjJ,EAAE,OAAO,EAAE,gBAAgB,EAAE,EAAE,EAAE,kDAAkD,EAAE,CAAC,CAAC;AAC3F,CAAC;AAED,MAAM,CAAC,MAAM,QAAQ,GAAG,UAAU,EAAE,CAAC;AAErC,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,QAAwB,EACxB,OAAwB,EACxB,MAAc;IAEd,MAAM,EAAE,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;IAC/B,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;IAElC,IAAI,CAAC,MAAM,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC;QACrD,MAAM,KAAK,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC;QACxC,IAAI,MAAM,EAAE,CAAC;YACX,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,IAAI,SAAS,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,MAAM,CAAC,WAAW,EAAE,EAAE,EAAE,MAAM,CAAC,WAAW,EAAE,EAAE,EAAE,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;QACrI,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,IAAI,CAAC,mBAAmB,CAAC,OAAO,EAAE,QAAQ,CAAC,EAAE,eAAe,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC;QACtF,CAAC;QACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;IAED,IAAI,MAAM,KAAK,OAAO;QAAE,OAAO,CAAC,MAAM,SAAS,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;IAC1E,IAAI,MAAM,KAAK,UAAU;QAAE,OAAO,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAElE,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACtB,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,gBAAgB,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;QACxD,IAAI,CAAC,GAAG;YAAE,OAAO,mBAAmB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;QACxD,OAAO,CAAC,MAAM,YAAY,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,CAAC;IACvE,CAAC;IAED,OAAO,mBAAmB,CAAC,OAAO,EAAE,SAAS,EAAE,MAAM,CAAC,GAAG,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;AACxF,CAAC;AAED,MAAM,QAAQ,GAAG,cAAc,CAAC;IAC9B,KAAK,EAAE,EAAE,OAAO,EAAE,sBAAsB,EAAE,EAAE,EAAE,2BAA2B,EAAE;CAC5E,CAAC,CAAC"}
@@ -25,6 +25,7 @@ export class SessionService extends BaseSessionService {
25
25
  const now = Date.now();
26
26
  const row = {
27
27
  id: generateSessionId(),
28
+ locale: message.locale ?? 'zh-CN',
28
29
  adapter: String(message.$adapter),
29
30
  endpoint: message.$endpoint,
30
31
  channel_type: message.$channel.type,
@@ -1 +1 @@
1
- {"version":3,"file":"session-service.js","sourceRoot":"","sources":["../src/session-service.ts"],"names":[],"mappings":"AACA,OAAO,EACL,kBAAkB,EAClB,UAAU,EACV,iBAAiB,GAGlB,MAAM,mBAAmB,CAAC;AAK3B,MAAM,OAAO,cAAe,SAAQ,kBAAiC;IACnE,YAAY,EAAe;QACzB,KAAK,CAAC,EAAmD,EAAE;YACzD,MAAM,EAAE,KAAK;YACb,KAAK,EAAE,cAAc;YACrB,UAAU,EAAE,CAAC,WAAW,CAAC;YACzB,eAAe,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,KAAK,KAAK;gBACpD,CAAC,CAAC,CAAC;wBACC,MAAM,EAAE,OAAO,CAAC,SAAS;wBACzB,QAAQ,EAAE,OAAO,CAAC,WAAW;wBAC7B,MAAM,EAAE,KAAK;wBACb,KAAK,EAAE,OAAO,CAAC,WAAW,GAAG,EAAE;qBAChC,CAAC;gBACJ,CAAC,CAAC,OAAO,CAAC,MAAM,KAAK,MAAM;oBACzB,CAAC,CAAC,CAAC;4BACC,MAAM,EAAE,OAAO,CAAC,SAAS;4BACzB,QAAQ,EAAE,OAAO,CAAC,WAAW;4BAC7B,MAAM,EAAE,MAAM;yBACf,CAAC;oBACJ,CAAC,CAAC,EAAE;SACT,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,OAAwB;QAC1C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,GAAG,GAAkB;YACzB,EAAE,EAAE,iBAAiB,EAAE;YACvB,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC;YACjC,QAAQ,EAAE,OAAO,CAAC,SAAS;YAC3B,YAAY,EAAE,OAAO,CAAC,QAAQ,CAAC,IAAI;YACnC,UAAU,EAAE,OAAO,CAAC,QAAQ,CAAC,EAAE;YAC/B,WAAW,EAAE,UAAU,CAAC,OAAO,CAAC;YAChC,SAAS,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE;YAC7B,WAAW,EAAE,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE;YAC/D,WAAW,EAAE,CAAC;YACd,QAAQ,EAAE,CAAC;YACX,KAAK,EAAE,CAAC;YACR,MAAM,EAAE,QAAQ;YAChB,UAAU,EAAE,GAAG;YACf,UAAU,EAAE,GAAG;SAChB,CAAC;QACF,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;CACF;AAED,MAAM,UAAU,cAAc,CAAC,EAAe;IAC5C,OAAO,IAAI,cAAc,CAAC,EAAE,CAAC,CAAC;AAChC,CAAC"}
1
+ {"version":3,"file":"session-service.js","sourceRoot":"","sources":["../src/session-service.ts"],"names":[],"mappings":"AACA,OAAO,EACL,kBAAkB,EAClB,UAAU,EACV,iBAAiB,GAGlB,MAAM,mBAAmB,CAAC;AAK3B,MAAM,OAAO,cAAe,SAAQ,kBAAiC;IACnE,YAAY,EAAe;QACzB,KAAK,CAAC,EAAmD,EAAE;YACzD,MAAM,EAAE,KAAK;YACb,KAAK,EAAE,cAAc;YACrB,UAAU,EAAE,CAAC,WAAW,CAAC;YACzB,eAAe,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,KAAK,KAAK;gBACpD,CAAC,CAAC,CAAC;wBACC,MAAM,EAAE,OAAO,CAAC,SAAS;wBACzB,QAAQ,EAAE,OAAO,CAAC,WAAW;wBAC7B,MAAM,EAAE,KAAK;wBACb,KAAK,EAAE,OAAO,CAAC,WAAW,GAAG,EAAE;qBAChC,CAAC;gBACJ,CAAC,CAAC,OAAO,CAAC,MAAM,KAAK,MAAM;oBACzB,CAAC,CAAC,CAAC;4BACC,MAAM,EAAE,OAAO,CAAC,SAAS;4BACzB,QAAQ,EAAE,OAAO,CAAC,WAAW;4BAC7B,MAAM,EAAE,MAAM;yBACf,CAAC;oBACJ,CAAC,CAAC,EAAE;SACT,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,OAAwB;QAC1C,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,GAAG,GAAkB;YACzB,EAAE,EAAE,iBAAiB,EAAE;YACvB,MAAM,EAAE,OAAO,CAAC,MAAM,IAAI,OAAO;YACjC,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC;YACjC,QAAQ,EAAE,OAAO,CAAC,SAAS;YAC3B,YAAY,EAAE,OAAO,CAAC,QAAQ,CAAC,IAAI;YACnC,UAAU,EAAE,OAAO,CAAC,QAAQ,CAAC,EAAE;YAC/B,WAAW,EAAE,UAAU,CAAC,OAAO,CAAC;YAChC,SAAS,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE;YAC7B,WAAW,EAAE,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE;YAC/D,WAAW,EAAE,CAAC;YACd,QAAQ,EAAE,CAAC;YACX,KAAK,EAAE,CAAC;YACR,MAAM,EAAE,QAAQ;YAChB,UAAU,EAAE,GAAG;YACf,UAAU,EAAE,GAAG;SAChB,CAAC;QACF,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAC7B,CAAC;CACF;AAED,MAAM,UAAU,cAAc,CAAC,EAAe;IAC5C,OAAO,IAAI,cAAc,CAAC,EAAE,CAAC,CAAC;AAChC,CAAC"}
package/lib/view.js CHANGED
@@ -1,45 +1,46 @@
1
+ import { createMessages } from 'zhin.js/i18n';
1
2
  import { buildChoiceKeyboard } from '@zhin.js/game-kit';
2
- import { MOVE_LABELS, RPS_PREFIX, WIN_TARGET } from './engine.js';
3
+ import { moveLabel, RPS_PREFIX, WIN_TARGET } from './engine.js';
3
4
  export function buildRpsView(session, lastRound, channelType) {
4
5
  const terminal = session.status !== 'active';
5
6
  const lines = [
6
- '✊✋✌️ **猜拳对决**',
7
+ messages(session.locale ?? undefined, 'text1'),
7
8
  '',
8
- `比分 · 你 **${session.player_wins}** : **${session.bot_wins}** 机器人(先 ${WIN_TARGET} 胜)`,
9
+ messages(session.locale ?? undefined, 'text2', { p0: session.player_wins, p1: session.bot_wins, p2: WIN_TARGET }),
9
10
  ];
10
11
  if (lastRound) {
11
12
  lines.push('');
12
- lines.push(`你出 ${MOVE_LABELS[lastRound.player]},机器人出 ${MOVE_LABELS[lastRound.bot]}`);
13
+ lines.push(messages(session.locale ?? undefined, 'text3', { p0: moveLabel(lastRound.player, session.locale), p1: moveLabel(lastRound.bot, session.locale) }));
13
14
  lines.push(lastRound.result === 0
14
- ? '🤝 平局!'
15
+ ? messages(session.locale ?? undefined, 'text4')
15
16
  : lastRound.result === 1
16
- ? '🎉 你赢了这一局!'
17
- : '😅 机器人赢了这一局。');
17
+ ? messages(session.locale ?? undefined, 'text5')
18
+ : messages(session.locale ?? undefined, 'text6'));
18
19
  }
19
20
  if (terminal) {
20
21
  lines.push('');
21
22
  if (session.status === 'won')
22
- lines.push('🏆 **你赢得比赛!**');
23
+ lines.push(messages(session.locale ?? undefined, 'text7'));
23
24
  else if (session.status === 'lost')
24
- lines.push('💀 **机器人赢得比赛。**');
25
+ lines.push(messages(session.locale ?? undefined, 'text8'));
25
26
  else
26
- lines.push('🏳️ **本局已放弃。**');
27
+ lines.push(messages(session.locale ?? undefined, 'text9'));
27
28
  }
28
29
  else if (!lastRound) {
29
- lines.push('', '出拳吧!');
30
+ lines.push('', messages(session.locale ?? undefined, 'text10'));
30
31
  }
31
32
  else {
32
- lines.push('', '继续出拳:');
33
+ lines.push('', messages(session.locale ?? undefined, 'text11'));
33
34
  }
34
35
  const choices = terminal
35
- ? [{ id: 'restart', label: '🔄 再来一局', style: 'primary', keepEnabledWhenTerminal: true }]
36
+ ? [{ id: 'restart', label: messages(session.locale ?? undefined, 'text12'), style: 'primary', keepEnabledWhenTerminal: true }]
36
37
  : [
37
38
  ...['rock', 'paper', 'scissors'].map((m) => ({
38
39
  id: m,
39
- label: MOVE_LABELS[m],
40
+ label: moveLabel(m, session.locale),
40
41
  style: 'secondary',
41
42
  })),
42
- { id: 'quit', label: '🏳️ 放弃', style: 'danger' },
43
+ { id: 'quit', label: messages(session.locale ?? undefined, 'text13'), style: 'danger' },
43
44
  ];
44
45
  return buildChoiceKeyboard({
45
46
  gamePrefix: RPS_PREFIX,
@@ -48,9 +49,25 @@ export function buildRpsView(session, lastRound, channelType) {
48
49
  choices,
49
50
  terminal,
50
51
  buttonsPerRow: 3,
51
- fallbackHint: '回复数字:1石头 2布 3剪刀 4放弃',
52
+ fallbackHint: messages(session.locale ?? undefined, 'text14'),
52
53
  interactionProfile: terminal ? 'terminal' : 'gameplay',
53
54
  channelType,
54
55
  });
55
56
  }
57
+ const messages = createMessages({
58
+ text1: { 'zh-CN': "✊✋✌️ **猜拳对决**", en: "✊✋✌️ **Rock Paper Scissors**" },
59
+ text2: { 'zh-CN': "比分 · 你 **{p0}** : **{p1}** 机器人(先 {p2} 胜)", en: "Score · You **{p0}** : **{p1}** Bot (first to {p2} wins)" },
60
+ text3: { 'zh-CN': "你出 {p0},机器人出 {p1}", en: "You played {p0}; the bot played {p1}" },
61
+ text4: { 'zh-CN': "🤝 平局!", en: "🤝 Draw!" },
62
+ text5: { 'zh-CN': "🎉 你赢了这一局!", en: "🎉 You won this round!" },
63
+ text6: { 'zh-CN': "😅 机器人赢了这一局。", en: "😅 The bot won this round." },
64
+ text7: { 'zh-CN': "🏆 **你赢得比赛!**", en: "🏆 **You won the match!**" },
65
+ text8: { 'zh-CN': "💀 **机器人赢得比赛。**", en: "💀 **The bot won the match.**" },
66
+ text9: { 'zh-CN': "🏳️ **本局已放弃。**", en: "🏳️ **You quit this match.**" },
67
+ text10: { 'zh-CN': "出拳吧!", en: "Choose your move!" },
68
+ text11: { 'zh-CN': "继续出拳:", en: "Choose your next move:" },
69
+ text12: { 'zh-CN': "🔄 再来一局", en: "🔄 Play again" },
70
+ text13: { 'zh-CN': "🏳️ 放弃", en: "🏳️ Quit" },
71
+ text14: { 'zh-CN': "回复数字:1石头 2布 3剪刀 4放弃", en: "Reply with a number: 1 Rock · 2 Paper · 3 Scissors · 4 Quit" },
72
+ });
56
73
  //# sourceMappingURL=view.js.map
package/lib/view.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"view.js","sourceRoot":"","sources":["../src/view.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AAGxD,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,UAAU,EAAgB,MAAM,aAAa,CAAC;AAEhF,MAAM,UAAU,YAAY,CAC1B,OAAsB,EACtB,SAAgE,EAChE,WAAoB;IAEpB,MAAM,QAAQ,GAAG,OAAO,CAAC,MAAM,KAAK,QAAQ,CAAC;IAC7C,MAAM,KAAK,GAAG;QACZ,eAAe;QACf,EAAE;QACF,YAAY,OAAO,CAAC,WAAW,UAAU,OAAO,CAAC,QAAQ,YAAY,UAAU,KAAK;KACrF,CAAC;IAEF,IAAI,SAAS,EAAE,CAAC;QACd,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,MAAM,WAAW,CAAC,SAAS,CAAC,MAAM,CAAC,SAAS,WAAW,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QACrF,KAAK,CAAC,IAAI,CACR,SAAS,CAAC,MAAM,KAAK,CAAC;YACpB,CAAC,CAAC,QAAQ;YACV,CAAC,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC;gBACtB,CAAC,CAAC,YAAY;gBACd,CAAC,CAAC,cAAc,CACrB,CAAC;IACJ,CAAC;IAED,IAAI,QAAQ,EAAE,CAAC;QACb,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,IAAI,OAAO,CAAC,MAAM,KAAK,KAAK;YAAE,KAAK,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;aACrD,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM;YAAE,KAAK,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;;YAC7D,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC;IACpC,CAAC;SAAM,IAAI,CAAC,SAAS,EAAE,CAAC;QACtB,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IACzB,CAAC;SAAM,CAAC;QACN,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,OAAO,CAAC,CAAC;IAC1B,CAAC;IAED,MAAM,OAAO,GAAG,QAAQ;QACtB,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,SAAkB,EAAE,uBAAuB,EAAE,IAAI,EAAE,CAAC;QACjG,CAAC,CAAC;YACE,GAAI,CAAC,MAAM,EAAE,OAAO,EAAE,UAAU,CAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBAC1D,EAAE,EAAE,CAAC;gBACL,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC;gBACrB,KAAK,EAAE,WAAoB;aAC5B,CAAC,CAAC;YACH,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAiB,EAAE;SAC1D,CAAC;IAEN,OAAO,mBAAmB,CAAC;QACzB,UAAU,EAAE,UAAU;QACtB,SAAS,EAAE,OAAO,CAAC,EAAE;QACrB,SAAS,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC;QAC3B,OAAO;QACP,QAAQ;QACR,aAAa,EAAE,CAAC;QAChB,YAAY,EAAE,qBAAqB;QACnC,kBAAkB,EAAE,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU;QACtD,WAAW;KACZ,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"view.js","sourceRoot":"","sources":["../src/view.ts"],"names":[],"mappings":"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"}
@@ -1,18 +1,20 @@
1
1
  // Generated by build-plugin-runtime-entries.mjs. Do not edit.
2
2
  import { defineGameCommandAliasMiddleware, isRpsAction, messageFromCommandInput, normalizeRpsAction, } from '@zhin.js/game-kit';
3
- import { RPS_HELP, runRpsCommand } from "../../lib/rps-command.js";
3
+ import { getRpsHelp, runRpsCommand } from "../../lib/rps-command.js";
4
4
  import { resolveGameServices } from "../../lib/runtime-store.js";
5
5
  export default defineGameCommandAliasMiddleware({
6
6
  aliases: ['猜拳', 'rps'],
7
7
  async run(action, input, context) {
8
+ const message = messageFromCommandInput(input, {
9
+ formatCommand: (path) => context.input.formatCommand?.(path, context.owner.id),
10
+ });
8
11
  const normalized = normalizeRpsAction(String(action ?? ''));
9
12
  if (normalized === 'help')
10
- return RPS_HELP;
13
+ return getRpsHelp(message);
11
14
  // action 无法识别:放行给后续中间件,避免劫持普通聊天
12
15
  if (!isRpsAction(normalized))
13
16
  return null;
14
17
  const services = resolveGameServices(context);
15
- const message = messageFromCommandInput(input);
16
18
  return runRpsCommand(services, message, normalized);
17
19
  },
18
20
  });
@@ -4,18 +4,20 @@ import {
4
4
  messageFromCommandInput,
5
5
  normalizeRpsAction,
6
6
  } from '@zhin.js/game-kit';
7
- import { RPS_HELP, runRpsCommand } from '../../src/rps-command.js';
7
+ import { getRpsHelp, runRpsCommand } from '../../src/rps-command.js';
8
8
  import { resolveGameServices } from '../../src/runtime-store.js';
9
9
 
10
10
  export default defineGameCommandAliasMiddleware({
11
11
  aliases: ['猜拳', 'rps'],
12
12
  async run(action, input, context) {
13
+ const message = messageFromCommandInput(input, {
14
+ formatCommand: (path) => context.input.formatCommand?.(path, context.owner.id),
15
+ });
13
16
  const normalized = normalizeRpsAction(String(action ?? ''));
14
- if (normalized === 'help') return RPS_HELP;
17
+ if (normalized === 'help') return getRpsHelp(message);
15
18
  // action 无法识别:放行给后续中间件,避免劫持普通聊天
16
19
  if (!isRpsAction(normalized)) return null;
17
20
  const services = resolveGameServices(context);
18
- const message = messageFromCommandInput(input);
19
21
  return runRpsCommand(services, message, normalized);
20
22
  },
21
23
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zhin.js/plugin-rps",
3
- "version": "1.1.15",
3
+ "version": "1.1.17",
4
4
  "description": "Zhin.js 猜拳游戏 — 石头剪刀布三局两胜 (Plugin Runtime)",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -23,13 +23,13 @@
23
23
  ],
24
24
  "license": "MIT",
25
25
  "dependencies": {
26
- "@zhin.js/core": "1.1.50",
27
- "@zhin.js/game-kit": "1.1.15"
26
+ "@zhin.js/core": "1.1.52",
27
+ "@zhin.js/game-kit": "1.1.17"
28
28
  },
29
29
  "devDependencies": {
30
30
  "typescript": "^6.0.3",
31
31
  "vitest": "^4.1.10",
32
- "zhin.js": "1.1.15"
32
+ "zhin.js": "1.1.17"
33
33
  },
34
34
  "repository": {
35
35
  "type": "git",
@@ -66,9 +66,9 @@
66
66
  "plugins": []
67
67
  },
68
68
  "peerDependencies": {
69
- "@zhin.js/command": "^1.1.10",
70
- "@zhin.js/middleware": "^1.1.9",
71
- "zhin.js": "^1.1.15"
69
+ "@zhin.js/command": "^1.1.11",
70
+ "@zhin.js/middleware": "^1.1.10",
71
+ "zhin.js": "^1.1.17"
72
72
  },
73
73
  "peerDependenciesMeta": {
74
74
  "@zhin.js/command": {
package/plugin.js CHANGED
@@ -15,6 +15,10 @@ export default defineGamePlugin({
15
15
  displayName: 'RPS',
16
16
  },
17
17
  game: {
18
+ commandPath: 'rps',
19
+ titleI18n: { en: 'Rock Paper Scissors' },
20
+ descriptionI18n: { en: 'Play rock, paper, scissors against the bot' },
21
+ quickStartI18n: { en: 'start' },
18
22
  id: 'rps',
19
23
  title: '猜拳对决',
20
24
  icon: '✊',
package/src/engine.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { createMessages, type Locale } from 'zhin.js/i18n';
1
2
  import { secureRandomItem } from '@zhin.js/game-kit';
2
3
 
3
4
  export const RPS_PREFIX = 'rps';
@@ -44,3 +45,6 @@ export function parseMove(raw: string): RpsMove | null {
44
45
  }
45
46
 
46
47
  export const WIN_TARGET = 3;
48
+
49
+ const moveMessages = createMessages({ rock: { 'zh-CN': '✊ 石头', en: '✊ Rock' }, paper: { 'zh-CN': '✋ 布', en: '✋ Paper' }, scissors: { 'zh-CN': '✌️ 剪刀', en: '✌️ Scissors' } });
50
+ export function moveLabel(move: RpsMove, locale?: Locale | null): string { return moveMessages(locale ?? undefined, move); }
package/src/game-flow.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { createMessages, resolveLocale } from 'zhin.js/i18n';
1
2
  import type { GameMessageLike, GameReply } from '@zhin.js/game-kit';
2
3
  import type { RpsSessionRow } from './models.js';
3
4
  import {
@@ -29,11 +30,12 @@ export async function startGame(
29
30
  ): Promise<GameReply | undefined> {
30
31
  const ch = `${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`;
31
32
  const active = await services.getActiveByChannel(ch);
33
+ const locale = resolveLocale(active ? active.locale : message.locale);
32
34
  if (active) {
33
35
  if (active.player_id === message.$sender.id) {
34
- return '你已有进行中的猜拳,发送「猜拳 继续」刷新,或「猜拳 放弃」。';
36
+ return messages(locale, 'text1');
35
37
  }
36
- return `本频道 ${active.player_name} 正在猜拳对决中。`;
38
+ return messages(locale, 'text2', { p0: active.player_name });
37
39
  }
38
40
  const session = await services.createSession(message);
39
41
  return renderView(session, message);
@@ -46,11 +48,12 @@ export async function handleChoice(
46
48
  choiceId: string,
47
49
  ): Promise<GameReply | null> {
48
50
  const session = await services.getById(sessionId);
49
- if (!session) return '对局不存在。';
51
+ const locale = resolveLocale(session ? session.locale : message.locale);
52
+ if (!session) return messages(locale, 'text3');
50
53
  if (session.status !== 'active' && choiceId !== 'restart') {
51
- return '对局已结束,请点击再来一局。';
54
+ return messages(locale, 'text4');
52
55
  }
53
- if (session.player_id !== message.$sender.id) return '这是别人的对局。';
56
+ if (session.player_id !== message.$sender.id) return messages(locale, 'text5');
54
57
 
55
58
  if (choiceId === 'restart') {
56
59
  await services.updateSession(session.id, { status: 'aborted' });
@@ -62,7 +65,7 @@ export async function handleChoice(
62
65
  }
63
66
 
64
67
  const player = choiceId as RpsMove;
65
- if (!['rock', 'paper', 'scissors'].includes(player)) return '无效出拳。';
68
+ if (!['rock', 'paper', 'scissors'].includes(player)) return messages(locale, 'text6');
66
69
 
67
70
  const bot = randomBotMove();
68
71
  const result = resolveRound(player, bot);
@@ -94,8 +97,19 @@ export async function continueGame(
94
97
  `${message.$adapter}-${message.$endpoint}-${message.$channel.type}:${message.$channel.id}`,
95
98
  message.$sender.id,
96
99
  );
97
- if (!session) return '你没有进行中的猜拳,发送「猜拳 开始」。';
100
+ const locale = resolveLocale(session ? session.locale : message.locale);
101
+ if (!session) return messages(locale, 'text7');
98
102
  return renderView(session, message);
99
103
  }
100
104
 
101
105
  export { RPS_PREFIX };
106
+
107
+ const messages = createMessages({
108
+ text1: { 'zh-CN': "你已有进行中的猜拳,请使用当前对局的操作入口。", en: "You already have an active game. Continue using its controls." },
109
+ text2: { 'zh-CN': "本频道 {p0} 正在猜拳对决中。", en: "{p0} is playing rock, paper, scissors in this channel." },
110
+ text3: { 'zh-CN': "对局不存在。", en: "This game no longer exists." },
111
+ text4: { 'zh-CN': "对局已结束,请点击再来一局。", en: "This game has ended. Choose Play again." },
112
+ text5: { 'zh-CN': "这是别人的对局。", en: "This game belongs to another player." },
113
+ text6: { 'zh-CN': "无效出拳。", en: "Invalid move." },
114
+ text7: { 'zh-CN': "你没有进行中的猜拳,请使用当前对局的操作入口。", en: "You have no active rock, paper, scissors game." },
115
+ });
package/src/models.ts CHANGED
@@ -6,6 +6,7 @@ declare module '@zhin.js/core' {
6
6
  interface Models {
7
7
  rps_sessions: {
8
8
  id: string;
9
+ locale?: 'zh-CN' | 'en' | null;
9
10
  adapter: string;
10
11
  endpoint: string;
11
12
  channel_type: string;
@@ -27,10 +28,11 @@ export type RpsSessionRow = Models['rps_sessions'];
27
28
 
28
29
 
29
30
  export function defineHostTables(
30
- db: { define: (name: string, definition: Record<string, unknown>) => void },
31
+ db: { define: (name: string, definition: Record<string, unknown>, options?: { readonly addColumns?: readonly string[] }) => void },
31
32
  ): void {
32
33
  db.define('rps_sessions', {
33
34
  id: { type: 'text', primary: true },
35
+ locale: { type: 'text', nullable: true },
34
36
  adapter: { type: 'text', nullable: false },
35
37
  endpoint: { type: 'text', nullable: false },
36
38
  channel_type: { type: 'text', nullable: false },
@@ -44,5 +46,5 @@ export function defineHostTables(
44
46
  status: { type: 'text', default: 'active' },
45
47
  updated_at: { type: 'bigint', default: 0 },
46
48
  created_at: { type: 'bigint', default: 0 },
47
- });
49
+ }, { addColumns: ['locale'] });
48
50
  }
@@ -1,18 +1,14 @@
1
- import {
2
- channelKey,
3
- type GameMessageLike,
4
- type GameReply,
5
- } from '@zhin.js/game-kit';
1
+ import { formatGameHelp, gameCommandFeedback, gameCommandHint, channelKey, type GameMessageLike, type GameReply } from '@zhin.js/game-kit';
2
+ import { createMessages } from 'zhin.js/i18n';
6
3
  import { continueGame, handleChoice, startGame } from './game-flow.js';
7
4
  import type { SessionService } from './session-service.js';
8
5
 
9
- export const RPS_HELP = [
10
- '✊✋✌️ 猜拳对决(三局两胜)',
11
- '猜拳 / rps — 帮助',
12
- '猜拳 开始 — 新对局',
13
- '猜拳 继续 — 刷新界面',
14
- '猜拳 放弃 — 结束对局',
15
- ].join('\n');
6
+ export function getRpsHelp(message: Pick<GameMessageLike, 'locale' | 'formatCommand'> = {}): string {
7
+ return formatGameHelp(message, { 'zh-CN': "✊✋✌️ 猜拳对决(三局两胜)", en: "✊✋✌️ Rock Paper Scissors (best of three)" }, 'rps', ['start', 'continue', 'quit'],
8
+ { 'zh-CN': "点击按钮或回复选项数字出拳。", en: "Choose a button or reply with its option number." });
9
+ }
10
+
11
+ export const RPS_HELP = getRpsHelp();
16
12
 
17
13
  export async function runRpsCommand(
18
14
  services: SessionService,
@@ -24,11 +20,11 @@ export async function runRpsCommand(
24
20
 
25
21
  if (!action || action === 'help') {
26
22
  const active = await services.getActiveByChannel(ch);
27
- const lines = [RPS_HELP, ''];
23
+ const lines = [getRpsHelp(message), ''];
28
24
  if (active) {
29
- lines.push(`进行中:${active.player_name} · ${active.player_wins}:${active.bot_wins}`);
25
+ lines.push(messages(active.locale ?? undefined, 'text1', { p0: active.player_name, p1: active.player_wins, p2: active.bot_wins }));
30
26
  } else {
31
- lines.push('暂无对局,发送「猜拳 开始」或从游戏大厅进入。');
27
+ lines.push(gameCommandFeedback(message, 'noGame'), gameCommandHint(message, 'rps'));
32
28
  }
33
29
  return lines.join('\n');
34
30
  }
@@ -38,9 +34,13 @@ export async function runRpsCommand(
38
34
 
39
35
  if (action === 'quit') {
40
36
  const row = await services.getActiveForUser(ch, userId);
41
- if (!row) return '你没有进行中的猜拳。';
37
+ if (!row) return gameCommandFeedback(message, 'noGame');
42
38
  return (await handleChoice(services, message, row.id, 'quit')) ?? '';
43
39
  }
44
40
 
45
- return `未知子命令:${action}\n\n${RPS_HELP}`;
41
+ return gameCommandFeedback(message, 'unknown', action) + '\n\n' + getRpsHelp(message);
46
42
  }
43
+
44
+ const messages = createMessages({
45
+ text1: { 'zh-CN': "进行中:{p0} · {p1}:{p2}", en: "Playing: {p0} · {p1}:{p2}" },
46
+ });
@@ -37,6 +37,7 @@ export class SessionService extends BaseSessionService<RpsSessionRow> {
37
37
  const now = Date.now();
38
38
  const row: RpsSessionRow = {
39
39
  id: generateSessionId(),
40
+ locale: message.locale ?? 'zh-CN',
40
41
  adapter: String(message.$adapter),
41
42
  endpoint: message.$endpoint,
42
43
  channel_type: message.$channel.type,
package/src/view.ts CHANGED
@@ -1,7 +1,8 @@
1
+ import { createMessages } from 'zhin.js/i18n';
1
2
  import { buildChoiceKeyboard } from '@zhin.js/game-kit';
2
3
  import type { SendContent } from '@zhin.js/core/runtime';
3
4
  import type { RpsSessionRow } from './models.js';
4
- import { MOVE_LABELS, RPS_PREFIX, WIN_TARGET, type RpsMove } from './engine.js';
5
+ import { moveLabel, RPS_PREFIX, WIN_TARGET, type RpsMove } from './engine.js';
5
6
 
6
7
  export function buildRpsView(
7
8
  session: RpsSessionRow,
@@ -10,43 +11,43 @@ export function buildRpsView(
10
11
  ): SendContent {
11
12
  const terminal = session.status !== 'active';
12
13
  const lines = [
13
- '✊✋✌️ **猜拳对决**',
14
+ messages(session.locale ?? undefined, 'text1'),
14
15
  '',
15
- `比分 · 你 **${session.player_wins}** : **${session.bot_wins}** 机器人(先 ${WIN_TARGET} 胜)`,
16
+ messages(session.locale ?? undefined, 'text2', { p0: session.player_wins, p1: session.bot_wins, p2: WIN_TARGET }),
16
17
  ];
17
18
 
18
19
  if (lastRound) {
19
20
  lines.push('');
20
- lines.push(`你出 ${MOVE_LABELS[lastRound.player]},机器人出 ${MOVE_LABELS[lastRound.bot]}`);
21
+ lines.push(messages(session.locale ?? undefined, 'text3', { p0: moveLabel(lastRound.player, session.locale), p1: moveLabel(lastRound.bot, session.locale) }));
21
22
  lines.push(
22
23
  lastRound.result === 0
23
- ? '🤝 平局!'
24
+ ? messages(session.locale ?? undefined, 'text4')
24
25
  : lastRound.result === 1
25
- ? '🎉 你赢了这一局!'
26
- : '😅 机器人赢了这一局。',
26
+ ? messages(session.locale ?? undefined, 'text5')
27
+ : messages(session.locale ?? undefined, 'text6'),
27
28
  );
28
29
  }
29
30
 
30
31
  if (terminal) {
31
32
  lines.push('');
32
- if (session.status === 'won') lines.push('🏆 **你赢得比赛!**');
33
- else if (session.status === 'lost') lines.push('💀 **机器人赢得比赛。**');
34
- else lines.push('🏳️ **本局已放弃。**');
33
+ if (session.status === 'won') lines.push(messages(session.locale ?? undefined, 'text7'));
34
+ else if (session.status === 'lost') lines.push(messages(session.locale ?? undefined, 'text8'));
35
+ else lines.push(messages(session.locale ?? undefined, 'text9'));
35
36
  } else if (!lastRound) {
36
- lines.push('', '出拳吧!');
37
+ lines.push('', messages(session.locale ?? undefined, 'text10'));
37
38
  } else {
38
- lines.push('', '继续出拳:');
39
+ lines.push('', messages(session.locale ?? undefined, 'text11'));
39
40
  }
40
41
 
41
42
  const choices = terminal
42
- ? [{ id: 'restart', label: '🔄 再来一局', style: 'primary' as const, keepEnabledWhenTerminal: true }]
43
+ ? [{ id: 'restart', label: messages(session.locale ?? undefined, 'text12'), style: 'primary' as const, keepEnabledWhenTerminal: true }]
43
44
  : [
44
45
  ...(['rock', 'paper', 'scissors'] as RpsMove[]).map((m) => ({
45
46
  id: m,
46
- label: MOVE_LABELS[m],
47
+ label: moveLabel(m, session.locale),
47
48
  style: 'secondary' as const,
48
49
  })),
49
- { id: 'quit', label: '🏳️ 放弃', style: 'danger' as const },
50
+ { id: 'quit', label: messages(session.locale ?? undefined, 'text13'), style: 'danger' as const },
50
51
  ];
51
52
 
52
53
  return buildChoiceKeyboard({
@@ -56,8 +57,25 @@ export function buildRpsView(
56
57
  choices,
57
58
  terminal,
58
59
  buttonsPerRow: 3,
59
- fallbackHint: '回复数字:1石头 2布 3剪刀 4放弃',
60
+ fallbackHint: messages(session.locale ?? undefined, 'text14'),
60
61
  interactionProfile: terminal ? 'terminal' : 'gameplay',
61
62
  channelType,
62
63
  });
63
64
  }
65
+
66
+ const messages = createMessages({
67
+ text1: { 'zh-CN': "✊✋✌️ **猜拳对决**", en: "✊✋✌️ **Rock Paper Scissors**" },
68
+ text2: { 'zh-CN': "比分 · 你 **{p0}** : **{p1}** 机器人(先 {p2} 胜)", en: "Score · You **{p0}** : **{p1}** Bot (first to {p2} wins)" },
69
+ text3: { 'zh-CN': "你出 {p0},机器人出 {p1}", en: "You played {p0}; the bot played {p1}" },
70
+ text4: { 'zh-CN': "🤝 平局!", en: "🤝 Draw!" },
71
+ text5: { 'zh-CN': "🎉 你赢了这一局!", en: "🎉 You won this round!" },
72
+ text6: { 'zh-CN': "😅 机器人赢了这一局。", en: "😅 The bot won this round." },
73
+ text7: { 'zh-CN': "🏆 **你赢得比赛!**", en: "🏆 **You won the match!**" },
74
+ text8: { 'zh-CN': "💀 **机器人赢得比赛。**", en: "💀 **The bot won the match.**" },
75
+ text9: { 'zh-CN': "🏳️ **本局已放弃。**", en: "🏳️ **You quit this match.**" },
76
+ text10: { 'zh-CN': "出拳吧!", en: "Choose your move!" },
77
+ text11: { 'zh-CN': "继续出拳:", en: "Choose your next move:" },
78
+ text12: { 'zh-CN': "🔄 再来一局", en: "🔄 Play again" },
79
+ text13: { 'zh-CN': "🏳️ 放弃", en: "🏳️ Quit" },
80
+ text14: { 'zh-CN': "回复数字:1石头 2布 3剪刀 4放弃", en: "Reply with a number: 1 Rock · 2 Paper · 3 Scissors · 4 Quit" },
81
+ });