paseo-kanban 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/OVERVIEW.md ADDED
@@ -0,0 +1,35 @@
1
+ # Kanban
2
+
3
+ A lightweight, responsive Kanban board plugin for Paseo workspaces.
4
+
5
+ ## Features
6
+
7
+ - **Flexible swimlanes**: Add, delete, and rename lanes.
8
+ - **Rich task cards**: Edit task titles and multi-line descriptions, manage subtask checklists, and link tasks to Paseo projects.
9
+ - **Task completion**: Check a card or drag it into the completion lane to finish; uncheck or drag out to restore.
10
+ - **Workspace tabs and splits**: Open the board beside an agent or terminal with Paseo's native split controls, initially filtered to the workspace's project, or use the sidebar entry.
11
+ - **Smooth drag and drop**: Support intra-lane reordering and cross-lane movement.
12
+
13
+ ## Storage and requirements
14
+
15
+ - **Data and privacy**: Board data is stored locally in host-scoped plugin settings with revision checks for concurrent edits. No accounts, tokens, or external network requests are required.
16
+ - **Host requirement**: Paseo 0.8.0 or later.
17
+
18
+ ---
19
+
20
+ # 看板 (Kanban)
21
+
22
+ 专为 Paseo 工作区打造的轻量响应式看板插件。
23
+
24
+ ## 核心功能
25
+
26
+ - **灵活的泳道管理**:支持泳道增删与改名。
27
+ - **丰富的任务卡片**:支持任务标题与多行描述编辑、子步骤清单管理,以及关联 Paseo 项目。
28
+ - **任务完成与恢复**:通过卡片勾选或拖入完成泳道标记完成;取消勾选或拖出即可恢复。
29
+ - **工作区标签页与分屏**:支持通过 Paseo 原生分屏控件与 Agent、Terminal 并排打开,默认筛选工作区所属项目,或使用侧边栏入口。
30
+ - **流畅拖拽交互**:支持同泳道排序与跨泳道状态流转。
31
+
32
+ ## 存储与要求
33
+
34
+ - **数据与隐私**:看板数据保存在宿主本地插件设置中,具备版本并发冲突保护(CAS)。无需账号、Token 或任何外部网络请求。
35
+ - **宿主要求**:Paseo 0.8.0 或更高版本。
package/README.md CHANGED
@@ -2,27 +2,26 @@
2
2
 
3
3
  [简体中文](./README.zh-CN.md)
4
4
 
5
- A lightweight, responsive Kanban board plugin for [Paseo](https://paseo.sh) workspaces. Organize tasks across customizable swimlanes, break them down into subtasks, associate cards with native Paseo projects, and manage workflow status with intuitive drag-and-drop.
5
+ A lightweight, responsive Kanban board plugin for [Paseo](https://paseo.sh) workspaces.
6
6
 
7
7
  ---
8
8
 
9
9
  ## Features
10
10
 
11
- - **Flexible Swimlanes**: Default lanes (`To Plan`, `In Progress`, `Done`) with full support for adding, renaming, and deleting custom lanes.
11
+ - **Flexible Swimlanes**: Add, delete, and rename lanes.
12
12
  - **Rich Task Cards**:
13
- - Task title and multi-line markdown description.
14
- - Subtasks checklist with completion toggles and live progress tracking.
15
- - Native Paseo project association.
16
- - **Project Filtering**: Instantly filter board cards by linked Paseo project to keep context focused.
17
- - **Smooth Drag-and-Drop**: Real-time hit-testing for reordering cards within lanes and moving cards across lanes.
18
- - **Versioned State Persistence**: Persists board data through Paseo's settings API with optimistic concurrency control (CAS) to prevent race conditions and accidental overwrites.
13
+ - Task title and multi-line description editing.
14
+ - Subtasks checklist.
15
+ - Support linking tasks to projects created in Paseo.
16
+ - **Workspace Tabs and Splits**: Open the board beside an agent or terminal, initially filtered to the workspace's project, or use the sidebar entry.
17
+ - **Smooth Drag-and-Drop**: Support intra-lane reordering and cross-lane movement.
19
18
 
20
19
  ---
21
20
 
22
21
  ## Requirements
23
22
 
24
- - **Paseo Host Runtime Commitment**: `>= 0.8.0` (declared in `paseo-plugin.json`). As a Paseo workspace plugin, production runtime execution is managed and hosted by the Paseo application environment. No consumer-side Node version restriction is imposed in `package.json`.
25
- - **Development & CI Baseline**: Node.js 24 (pinned in `.nvmrc` and `.node-version`). Node 24 is required for local contributors and CI automation workflows running quality checks (`npm run check`), type stripping (`--experimental-strip-types`), and native test suites (`node --test`).
23
+ - **Paseo host**: `>= 0.8.0` (declared in `paseo-plugin.json`). The host runs the plugin.
24
+ - **Development and CI**: Node.js 24 (pinned in `.nvmrc` and `.node-version`) for checks, TypeScript stripping, and native tests.
26
25
 
27
26
  ---
28
27
 
@@ -30,7 +29,7 @@ A lightweight, responsive Kanban board plugin for [Paseo](https://paseo.sh) work
30
29
 
31
30
  ### Quick Install (Recommended)
32
31
 
33
- No manual build or git cloning needed. You can install directly via npm or GitHub:
32
+ Install directly from npm or GitHub:
34
33
 
35
34
  **Via NPM (Release package):**
36
35
 
@@ -56,7 +55,10 @@ Verify that the plugin is running:
56
55
  paseo plugin ls
57
56
  ```
58
57
 
59
- Once active, open Paseo. The **Kanban** icon (`PanelsTopLeft`) will appear in the sidebar. Click it to launch the board.
58
+ Open the board from either entry:
59
+
60
+ - **Sidebar → Kanban**: shows all tasks by default.
61
+ - **Workspace → `+` → Kanban**: initially filters to the workspace's project, with other filters available; use Paseo's native split controls to place it beside an agent or terminal.
60
62
 
61
63
  ### Local Development
62
64
 
@@ -66,7 +68,7 @@ To contribute or debug locally:
66
68
  # 1. Clone repository and install dependencies
67
69
  git clone https://github.com/breathi3552/paseo-kanban.git
68
70
  cd paseo-kanban
69
- npm install
71
+ npm ci
70
72
 
71
73
  # 2. Link this directory into your local Paseo daemon
72
74
  paseo plugin link .
@@ -76,56 +78,26 @@ paseo plugin link .
76
78
 
77
79
  ## Development & Testing
78
80
 
79
- ### Install Dependencies
81
+ Install dependencies and run the full quality check:
80
82
 
81
83
  ```bash
82
- npm install
83
- # or clean install:
84
84
  npm ci
85
+ npm run check
85
86
  ```
86
87
 
87
- ### Unified Quality Guardrails (Check)
88
+ Individual commands (`npm test`, `npm run typecheck`, `npm run lint`, `npm run format:check`, `npm run check:package`) are defined in [`package.json`](./package.json). For tag-based publishing, release sources of truth, recovery, and host acceptance, see the [development guide](./docs/development.md#21-标签发布github-actions).
88
89
 
89
- Runs typecheck, automated test suites, linting, format verification, and release package checks in sequence:
90
+ ---
90
91
 
91
- ```bash
92
- npm run check
93
- ```
92
+ ## Releases
94
93
 
95
- ### Individual Quality Tasks
96
-
97
- - **Package Verification**: Validates release package contents, entrypoints, and TypeScript AST relative imports:
98
- ```bash
99
- npm run check:package
100
- ```
101
- - **Run Tests**: Cross-platform auto-discovery of all `test/*.test.mjs` suites:
102
- ```bash
103
- npm test
104
- ```
105
- - **Type Checking**: Validates TypeScript types across client and server entry points:
106
- ```bash
107
- npm run typecheck
108
- ```
109
- - **Linting**: Static code analysis with ESLint:
110
- ```bash
111
- npm run lint
112
- ```
113
- - **Formatting**: Check or format code style with Prettier:
114
- ```bash
115
- npm run format:check
116
- npm run format
117
- ```
118
-
119
- Maintainers can publish a new GitHub Release and npm package in one run of the **Release to GitHub and npm** GitHub Action: select `patch`, `minor`, or `major`. Configure `NPM_TOKEN` and repository write permissions first. For setup, recovery, and manual host acceptance, see the [Development & Acceptance Guide](./docs/development.md#24-一键发布github-actions).
94
+ See the [0.1.4 release notes](./docs/releases/0.1.4.md). Each release's npm package and GitHub Release share the same version tag; GitHub includes the verified npm tarball. `main` may contain changes beyond the latest release.
120
95
 
121
96
  ---
122
97
 
123
98
  ## Architecture & Design
124
99
 
125
- The complete architectural breakdown and interactive visual diagram are archived in the repository:
126
-
127
- - **Interactive Architecture Viewer**: Open [`docs/architecture/paseo-kanban.architecture.html`](./docs/architecture/paseo-kanban.architecture.html) in your browser.
128
- - **Architecture Schema & Model**: [`docs/architecture/paseo-kanban.architecture.json`](./docs/architecture/paseo-kanban.architecture.json).
100
+ Core terminology and design decisions are documented in [`GLOSSARY.md`](./GLOSSARY.md) and [`docs/adr/`](./docs/adr/).
129
101
 
130
102
  ---
131
103
 
package/README.zh-CN.md CHANGED
@@ -2,27 +2,26 @@
2
2
 
3
3
  [English](./README.md)
4
4
 
5
- 专为 [Paseo](https://paseo.sh) 工作区打造的轻量响应式看板插件。支持自定义泳道分类、任务子步骤细化、原生 Paseo 项目关联筛选,以及跨泳道流畅拖拽管理。
5
+ 专为 [Paseo](https://paseo.sh) 工作区打造的轻量响应式看板插件。
6
6
 
7
7
  ---
8
8
 
9
9
  ## 核心功能
10
10
 
11
- - **灵活的泳道管理**:开箱即用三列基础泳道(`待规划`、`执行中`、`已完成`),支持自由添加、重命名与删除自定义泳道。
11
+ - **灵活的泳道管理**:支持泳道增删与改名。
12
12
  - **丰富的任务卡片**:
13
13
  - 任务标题与多行描述编辑。
14
- - 子步骤清单支持独立增删改、完成状态勾选及实时进度展示。
15
- - 支持关联本地已有的 Paseo 项目。
16
- - **项目维度筛选**:一键按关联的 Paseo 项目过滤看板卡片,聚焦当前目标。
17
- - **流畅拖拽交互**:精准的拖拽命中测试(Hit-Testing),支持同泳道排序与跨泳道状态流转。
18
- - **版本化数据持久化**:基于 Paseo 原生 settings API 存储,内置乐观并发版本控制(CAS),杜绝多会话覆写与状态不一致。
14
+ - 子步骤清单。
15
+ - 支持关联 Paseo 中创建的项目。
16
+ - **工作区标签页与分屏**:与 Agent、Terminal 并排打开看板,默认筛选工作区所属项目;或使用侧边栏入口。
17
+ - **流畅拖拽交互**:支持同泳道排序与跨泳道状态流转。
19
18
 
20
19
  ---
21
20
 
22
21
  ## 环境要求
23
22
 
24
- - **Paseo 宿主版本承诺**:`>= 0.8.0`(声明于 `paseo-plugin.json`)。作为 Paseo 工作区插件,插件的生产运行时环境由 Paseo 宿主应用提供并托管执行,不在 `package.json` 对消费端强加额外的 `engines.node` 限制。
25
- - **开发与 CI 环境基线**:Node.js 24(显式声明于 `.nvmrc` 与 `.node-version`)。本地参与开发、运行质量检查护栏(`npm run check`)、代码格式化、类型检查与自动化测试必须基于 Node 24,依赖其原生的 `--experimental-strip-types` 类型擦除与原生测试运行器(`node --test`)。
23
+ - **Paseo 宿主**:`>= 0.8.0`(声明于 `paseo-plugin.json`),由 Paseo 运行插件。
24
+ - **开发与 CI**:使用 Node.js 24(声明于 `.nvmrc` 与 `.node-version`)执行质量检查、TypeScript 类型擦除和原生测试。
26
25
 
27
26
  ---
28
27
 
@@ -30,7 +29,7 @@
30
29
 
31
30
  ### 快速安装(推荐)
32
31
 
33
- 无需克隆源码或手动编译,推荐直接使用 Paseo CLI 安装:
32
+ 通过 Paseo CLI 从 npm 或 GitHub 安装:
34
33
 
35
34
  **方式一:通过 NPM 官方包安装(推荐)**
36
35
 
@@ -56,7 +55,10 @@ paseo plugin add breathi3552/paseo-kanban --ref main
56
55
  paseo plugin ls
57
56
  ```
58
57
 
59
- 状态显示为 `running` 后打开 Paseo,侧边栏将出现 **看板** 入口(图标:`PanelsTopLeft`),点击即可进入看板。
58
+ 可从两个入口打开看板:
59
+
60
+ - **侧边栏 → 看板**:默认展示全部任务。
61
+ - **工作区 → `+` → 看板**:默认筛选工作区所属项目,可切换范围;使用 Paseo 原生分屏操作与 Agent、Terminal 等并排显示。
60
62
 
61
63
  ### 本地开发与调试
62
64
 
@@ -66,7 +68,7 @@ paseo plugin ls
66
68
  # 1. 克隆代码仓库并安装依赖
67
69
  git clone https://github.com/breathi3552/paseo-kanban.git
68
70
  cd paseo-kanban
69
- npm install
71
+ npm ci
70
72
 
71
73
  # 2. 将当前开发目录软链接至本地 Paseo 守护进程
72
74
  paseo plugin link .
@@ -76,58 +78,26 @@ paseo plugin link .
76
78
 
77
79
  ## 开发与测试
78
80
 
79
- ### 安装依赖
81
+ 安装依赖并运行完整检查:
80
82
 
81
83
  ```bash
82
- npm install
83
- # 或干净安装验证:
84
84
  npm ci
85
+ npm run check
85
86
  ```
86
87
 
87
- ### 统一质量护栏检查
88
+ 单项命令(`npm test`、`npm run typecheck`、`npm run lint`、`npm run format:check`、`npm run check:package`)见 [`package.json`](./package.json)。标签发布、事实来源、失败重试与宿主验收见[开发指南](./docs/development.md#21-标签发布github-actions)。
88
89
 
89
- 按顺序执行类型检查、自动化测试套件、静态代码检查、代码格式验证及发布包完整性检查:
90
+ ---
90
91
 
91
- ```bash
92
- npm run check
93
- ```
92
+ ## 版本发布
94
93
 
95
- ### 各独立质量命令
96
-
97
- - **发布包完整性检查**:静态校验发布包产物清单、入口完整性与 TypeScript AST 相对导入闭包:
98
- ```bash
99
- npm run check:package
100
- ```
101
- - **运行单元测试**:跨平台自动发现并执行所有 `test/*.test.mjs` 测试套件:
102
- ```bash
103
- npm test
104
- ```
105
- - **类型检查**:校验前端组件与服务端扩展的 TypeScript 类型完整性:
106
- ```bash
107
- npm run typecheck
108
- ```
109
- - **代码规范检查 (Lint)**:基于 ESLint 开展轻量静态检查:
110
- ```bash
111
- npm run lint
112
- ```
113
- - **代码格式检查与格式化 (Format)**:基于 Prettier 校验或自动格式化:
114
- ```bash
115
- npm run format:check
116
- npm run format
117
- ```
118
-
119
- 维护者可在 GitHub Actions 的 **Release to GitHub and npm** 工作流中选择 `patch` / `minor` / `major` 一键发布 GitHub Release 与 npm 包;首次使用需配置 `NPM_TOKEN` 和仓库写入权限。操作及失败重试说明见 [开发与宿主验收指南](./docs/development.md#24-一键发布github-actions)。
120
-
121
- 详细开发贡献流程、发布前检查机制与真实宿主环境手工验收指南,请参阅 [开发与宿主验收指南](./docs/development.md)。
94
+ 参见 [0.1.4 版本说明](./docs/releases/0.1.4.md)。每版 npm 包与 GitHub Release 对应同一个版本 tag,GitHub 附带经过验证的 npm tarball。`main` 可能包含最新发布版之后的改动。
122
95
 
123
96
  ---
124
97
 
125
98
  ## 架构设计
126
99
 
127
- 完整的插件架构图景与交互式全景模型已归档于仓库:
128
-
129
- - **交互式架构全景图**:直接使用浏览器打开 [`docs/architecture/paseo-kanban.architecture.html`](./docs/architecture/paseo-kanban.architecture.html) 查看。
130
- - **架构定义元数据**:[`docs/architecture/paseo-kanban.architecture.json`](./docs/architecture/paseo-kanban.architecture.json)。
100
+ 核心术语和架构决策见 [`GLOSSARY.md`](./GLOSSARY.md) 与 [`docs/adr/`](./docs/adr/)。
131
101
 
132
102
  ---
133
103
 
package/client/i18n.tsx CHANGED
@@ -1,7 +1,11 @@
1
- import { useState, useEffect, useMemo } from "react";
1
+ import { useState, useEffect, useMemo, createContext, useContext } from "react";
2
2
 
3
3
  export type SupportedLanguage = "zh" | "en";
4
4
 
5
+ export const I18nLanguageContext = createContext<SupportedLanguage | null>(
6
+ null,
7
+ );
8
+
5
9
  export type TranslationParams = Record<
6
10
  string,
7
11
  string | number | boolean | null | undefined
@@ -9,6 +13,19 @@ export type TranslationParams = Record<
9
13
 
10
14
  export const translations = {
11
15
  zh: {
16
+ "notification.taskCreated": "任务已创建",
17
+ "notification.taskUpdated": "任务已更新",
18
+ "notification.taskDeleted": "任务已删除",
19
+ "notification.laneCreated": "泳道已创建",
20
+ "notification.laneRenamed": "泳道已重命名",
21
+ "notification.laneDeleted": "泳道已删除",
22
+ "notification.taskSaveFailed": "任务保存失败,草稿已保留,请核实最新数据。",
23
+ "notification.taskDeleteFailed": "任务删除失败,请核实最新数据。",
24
+ "notification.laneSaveFailed": "泳道保存失败,草稿已保留,请核实最新数据。",
25
+ "notification.laneDeleteFailed": "泳道删除失败,请核实最新数据。",
26
+ "notification.taskReorderFailed": "任务移动失败,请刷新最新数据后重试。",
27
+ "notification.taskCompletionFailed":
28
+ "任务完成状态保存失败,请核实最新状态。",
12
29
  "kanban.sidebarTitle": "看板",
13
30
  "kanban.title": "任务看板",
14
31
  "kanban.loading": "正在加载看板数据...",
@@ -31,13 +48,18 @@ export const translations = {
31
48
  "lane.add": "+ 添加",
32
49
  "lane.manage": "管理",
33
50
  "lane.emptyHint": "暂无卡片,可点击右上角添加或拖动卡片至此",
51
+ "lane.emptyCompletionHint": "暂无已完成任务,可勾选任务或将卡片拖入此泳道",
52
+ "card.completeTask": "完成任务:{title}",
53
+ "card.reopenTask": "取消完成:{title}",
34
54
  "card.dragHandle": "拖动手柄",
35
55
  "card.subtasksCount": "子步骤 {completed}/{total}",
36
56
  "laneModal.titleEdit": "管理泳道",
37
57
  "laneModal.titleCreate": "新增泳道",
38
58
  "laneModal.nameLabel": "泳道名称 *",
39
59
  "laneModal.namePlaceholder": "例如:待测试、发布中...",
40
- "laneModal.cannotDeleteLast": "看板必须至少保留一条泳道,无法删除此泳道。",
60
+ "laneModal.cannotDeleteLast":
61
+ "看板必须至少保留一条普通泳道,无法删除此泳道。",
62
+ "laneModal.cannotDeleteCompletion": "完成泳道不可删除,可以修改名称。",
41
63
  "laneModal.cannotDeleteHasTasks":
42
64
  "此泳道当前包含 {count} 个任务,需清空或移走任务后方可删除。",
43
65
  "laneModal.deleteLane": "删除此泳道",
@@ -69,6 +91,24 @@ export const translations = {
69
91
  "taskModal.submitCreate": "创建",
70
92
  },
71
93
  en: {
94
+ "notification.taskCreated": "Task created",
95
+ "notification.taskUpdated": "Task updated",
96
+ "notification.taskDeleted": "Task deleted",
97
+ "notification.laneCreated": "Lane created",
98
+ "notification.laneRenamed": "Lane renamed",
99
+ "notification.laneDeleted": "Lane deleted",
100
+ "notification.taskSaveFailed":
101
+ "Task save failed. Draft preserved; check the latest data.",
102
+ "notification.taskDeleteFailed":
103
+ "Task deletion failed. Check the latest data.",
104
+ "notification.laneSaveFailed":
105
+ "Lane save failed. Draft preserved; check the latest data.",
106
+ "notification.laneDeleteFailed":
107
+ "Lane deletion failed. Check the latest data.",
108
+ "notification.taskReorderFailed":
109
+ "Task move failed. Refresh the latest data and try again.",
110
+ "notification.taskCompletionFailed":
111
+ "Task completion change failed. Check the latest state.",
72
112
  "kanban.sidebarTitle": "Kanban",
73
113
  "kanban.title": "Task Kanban",
74
114
  "kanban.loading": "Loading kanban board data...",
@@ -92,6 +132,10 @@ export const translations = {
92
132
  "lane.manage": "Manage",
93
133
  "lane.emptyHint":
94
134
  "No cards yet. Click '+' in the top right or drag cards here.",
135
+ "lane.emptyCompletionHint":
136
+ "No completed tasks. Check a task or drag it into this lane.",
137
+ "card.completeTask": "Mark {title} complete",
138
+ "card.reopenTask": "Mark {title} incomplete",
95
139
  "card.dragHandle": "Drag handle",
96
140
  "card.subtasksCount": "Subtasks {completed}/{total}",
97
141
  "laneModal.titleEdit": "Manage Lane",
@@ -99,7 +143,9 @@ export const translations = {
99
143
  "laneModal.nameLabel": "Lane Name *",
100
144
  "laneModal.namePlaceholder": "e.g., Testing, In Review...",
101
145
  "laneModal.cannotDeleteLast":
102
- "A kanban board must retain at least one lane. Cannot delete this lane.",
146
+ "A kanban board must retain at least one ordinary lane. Cannot delete this lane.",
147
+ "laneModal.cannotDeleteCompletion":
148
+ "The completion lane cannot be deleted. You can rename it.",
103
149
  "laneModal.cannotDeleteHasTasks":
104
150
  "This lane currently contains {count} tasks. Clear or move tasks before deleting.",
105
151
  "laneModal.deleteLane": "Delete Lane",
@@ -172,6 +218,7 @@ interface EnvironmentGlobals {
172
218
  };
173
219
  navigator?: {
174
220
  language?: string;
221
+ languages?: readonly string[];
175
222
  };
176
223
  window?: {
177
224
  addEventListener(
@@ -214,6 +261,12 @@ export function detectPaseoLanguage(
214
261
  } catch {}
215
262
  }
216
263
 
264
+ // Match Paseo's web system-language source before page/Intl defaults.
265
+ const navLocale = env.navigator?.languages?.[0] || env.navigator?.language;
266
+ if (navLocale) {
267
+ return normalizeLanguage(navLocale);
268
+ }
269
+
217
270
  const docLang = env.document?.documentElement?.lang;
218
271
  if (docLang) {
219
272
  return normalizeLanguage(docLang);
@@ -232,11 +285,6 @@ export function detectPaseoLanguage(
232
285
  return normalizeLanguage(intlLocale);
233
286
  }
234
287
 
235
- const navLocale = env.navigator?.language;
236
- if (navLocale) {
237
- return normalizeLanguage(navLocale);
238
- }
239
-
240
288
  return "en";
241
289
  }
242
290
 
@@ -323,6 +371,7 @@ export interface I18nContextValue {
323
371
  }
324
372
 
325
373
  export function useI18n(hostProps?: DetectLanguageOptions): I18nContextValue {
374
+ const inheritedLanguage = useContext(I18nLanguageContext);
326
375
  const hostLocale =
327
376
  hostProps?.locale ??
328
377
  hostProps?.language ??
@@ -341,14 +390,15 @@ export function useI18n(hostProps?: DetectLanguageOptions): I18nContextValue {
341
390
  });
342
391
  }, [hostLocale, hostProps]);
343
392
 
393
+ const language = hostLocale ? lang : (inheritedLanguage ?? lang);
344
394
  const tBound = useMemo(
345
395
  () => (key: TranslationKey, params?: TranslationParams) =>
346
- t(key, lang, params),
347
- [lang],
396
+ t(key, language, params),
397
+ [language],
348
398
  );
349
399
 
350
400
  return {
351
- language: lang,
401
+ language,
352
402
  t: tBound,
353
403
  };
354
404
  }