mirror of
https://github.com/kuaifan/dootask.git
synced 2026-07-21 21:48:00 +00:00
refactor(i18n): 完成前端国际化改造
This commit is contained in:
parent
c9b3515aef
commit
df6c1fc04d
@ -51,6 +51,7 @@ php .claude/skills/dootask-release/scripts/language.php diff
|
||||
```
|
||||
|
||||
输出 JSON:
|
||||
- `formatErrorCount > 0`:translate.json **已有条目**含 raw `(*)`/`(**)` key、字段结构错误、非法/不连续的参数编号或规范化重复 → **停止**,报告 `formatErrors`,交用户修复
|
||||
- `regexErrorCount > 0`:translate.json **已有条目**的占位符与某语言值不一致 → **停止**,报告 `regexErrors`,交用户修复(这是历史数据问题,不要自行猜测修改)
|
||||
- `redundantCount > 0`:translate.json 里有、但原文已删除的条目 → 仅作提示(apply 时会自动剔除,不致命)
|
||||
- `needsCount == 0`:无新文案 → **跳到 1.4 直接生成**
|
||||
@ -82,7 +83,7 @@ php .claude/skills/dootask-release/scripts/language.php diff
|
||||
php .claude/skills/dootask-release/scripts/language.php apply /tmp/dootask-release-translated.json
|
||||
```
|
||||
|
||||
脚本会校验字段完整性与占位符完整性、追加新条目、剔除冗余项,并按项目原生格式写回 `translate.json`。任一条不合格会报错停止,按提示修正翻译后重试。
|
||||
脚本会校验字段完整性与占位符完整性、追加新条目、剔除冗余项,并按项目原生格式写回 `translate.json`。参数化 key 必须使用 `(%T1)`/`(%M1)` 形式,禁止输入 raw `(*)`/`(**)`;编号须按出现顺序从 1 连续递增,各语言值可调整占位符顺序,但占位符的类型、编号和数量必须与 key 完全一致。输入 JSON 内相同或规范化后相同的 key 会被拒绝;已存在于 `translate.json` 的非待补项也会被拒绝,避免覆盖歧义。任一条不合格会明确报错并停止,按提示修正翻译后重试。
|
||||
|
||||
**1.4 生成前端/后端语言文件**
|
||||
|
||||
@ -90,7 +91,7 @@ php .claude/skills/dootask-release/scripts/language.php apply /tmp/dootask-relea
|
||||
php .claude/skills/dootask-release/scripts/language.php generate
|
||||
```
|
||||
|
||||
由 `translate.json` 字节级重新生成 `public/language/web/*.js` 与 `public/language/api/*.json`(排序/转义与项目原生工具完全一致,正常情况下 diff 只包含本次新增条目)。
|
||||
由 `translate.json` 字节级重新生成 `public/language/web/*.js` 与 `public/language/api/*.json`(排序/转义与项目原生工具完全一致,正常情况下 diff 只包含本次新增条目)。生成前会再次执行格式与占位符校验;存在 raw `(*)`/`(**)` key 或占位符错误时不会写入生成文件。
|
||||
|
||||
**1.5 报告**:用 `git status --short language public/language` 汇总本步改动,向用户报告新增了多少条翻译。
|
||||
|
||||
|
||||
@ -6,7 +6,8 @@
|
||||
//
|
||||
// 子命令:
|
||||
// language.php diff
|
||||
// —— 输出 JSON:needs(待翻译,key 已转成 (%T1)/(%M1) 形式) / redundants(冗余,提示) / regexErrors(占位符错乱,致命)
|
||||
// —— 输出 JSON:needs(待翻译,key 已转成 (%T1)/(%M1) 形式) / redundants(冗余,提示)
|
||||
// / formatErrors(raw 占位符、字段或编号错误,致命) / regexErrors(各语言占位符错乱,致命)
|
||||
// language.php apply <translated.json>
|
||||
// —— 把新翻译合并进 translate.json(追加 + 剔除冗余),不生成 public 文件
|
||||
// language.php generate
|
||||
@ -41,43 +42,136 @@ function read_generateds(): array
|
||||
return [$originals, $generateds];
|
||||
}
|
||||
|
||||
// ---- 公共:构建 translations 映射(normalizedKey -> obj),并收集冗余/占位符错乱 ----
|
||||
// ---- 公共:占位符与条目结构校验 ----
|
||||
function parameter_tokens(string $value): array
|
||||
{
|
||||
preg_match_all('/\(%[TM]\d+\)/', $value, $matches);
|
||||
return $matches[0];
|
||||
}
|
||||
|
||||
function normalize_key(string $key): string
|
||||
{
|
||||
return preg_replace(["/\(%T\d+\)/", "/\(%M\d+\)/"], ["(*)", "(**)"], $key);
|
||||
}
|
||||
|
||||
function validate_entry(array $obj, string $location, bool $requireTranslations): array
|
||||
{
|
||||
$formatErrors = [];
|
||||
$regexErrors = [];
|
||||
foreach ($GLOBALS['LANG_FIELDS'] as $field) {
|
||||
if (!array_key_exists($field, $obj)) {
|
||||
$formatErrors[] = ['location' => "$location.$field", 'message' => "缺少字段 $field"];
|
||||
} elseif (!is_string($obj[$field])) {
|
||||
$formatErrors[] = ['location' => "$location.$field", 'message' => "字段 $field 必须是字符串"];
|
||||
} elseif ($requireTranslations && $field !== 'key' && $field !== 'zh' && $obj[$field] === '') {
|
||||
$formatErrors[] = ['location' => "$location.$field", 'message' => "字段 $field 不得为空"];
|
||||
}
|
||||
}
|
||||
if (!isset($obj['key']) || !is_string($obj['key'])) {
|
||||
return [$formatErrors, $regexErrors];
|
||||
}
|
||||
|
||||
$key = $obj['key'];
|
||||
if (preg_match('/\(\*{1,2}\)/', $key)) {
|
||||
$formatErrors[] = [
|
||||
'location' => "$location.key",
|
||||
'message' => "key 不得包含 raw (*)/(**),必须使用 (%T1)/(%M1):$key",
|
||||
];
|
||||
}
|
||||
$withoutValidParameters = preg_replace('/\(%[TM]\d+\)/', '', $key);
|
||||
if (str_contains($withoutValidParameters, '(%')) {
|
||||
$formatErrors[] = ['location' => "$location.key", 'message' => "存在非法参数占位符:$key"];
|
||||
}
|
||||
|
||||
$keyTokens = parameter_tokens($key);
|
||||
foreach ($keyTokens as $index => $token) {
|
||||
preg_match('/\d+/', $token, $number);
|
||||
if ((int)$number[0] !== $index + 1) {
|
||||
$formatErrors[] = [
|
||||
'location' => "$location.key",
|
||||
'message' => "参数编号必须按出现顺序从 1 连续递增:$key",
|
||||
];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$expected = $keyTokens;
|
||||
sort($expected);
|
||||
foreach ($GLOBALS['LANG_FIELDS'] as $field) {
|
||||
if ($field === 'key' || !isset($obj[$field]) || !is_string($obj[$field]) || $obj[$field] === '') {
|
||||
continue;
|
||||
}
|
||||
$actual = parameter_tokens($obj[$field]);
|
||||
sort($actual);
|
||||
if ($actual !== $expected) {
|
||||
$regexErrors[] = [
|
||||
'location' => "$location.$field",
|
||||
'key' => $key,
|
||||
'field' => $field,
|
||||
'value' => $obj[$field],
|
||||
'expected' => $expected,
|
||||
'actual' => $actual,
|
||||
'message' => "参数占位符缺失、类型或编号不一致",
|
||||
];
|
||||
}
|
||||
}
|
||||
return [$formatErrors, $regexErrors];
|
||||
}
|
||||
|
||||
function print_validation_errors(array $formatErrors, array $regexErrors): void
|
||||
{
|
||||
foreach ($formatErrors as $error) {
|
||||
fwrite(STDERR, "格式错误 {$error['location']}:{$error['message']}\n");
|
||||
}
|
||||
foreach ($regexErrors as $error) {
|
||||
fwrite(STDERR, "占位符错误 {$error['location']}:{$error['message']};key={$error['key']}\n");
|
||||
}
|
||||
}
|
||||
|
||||
// ---- 公共:构建 translations 映射(normalizedKey -> obj),并收集冗余/格式/占位符错乱 ----
|
||||
function build_translations(array $originals): array
|
||||
{
|
||||
$translations = [];
|
||||
$redundants = [];
|
||||
$regrror = [];
|
||||
$regexErrors = [];
|
||||
$formatErrors = [];
|
||||
if (!file_exists("translate.json")) {
|
||||
fwrite(STDERR, "translate.json not exists\n");
|
||||
exit(1);
|
||||
}
|
||||
$tmps = json_decode(file_get_contents("translate.json"), true);
|
||||
foreach ($tmps as $obj) {
|
||||
if (!isset($obj['key'])) {
|
||||
if (!is_array($tmps)) {
|
||||
$formatErrors[] = ['location' => 'translate.json', 'message' => '根数据必须是 JSON 数组'];
|
||||
return [$translations, $redundants, $regexErrors, $formatErrors];
|
||||
}
|
||||
foreach ($tmps as $index => $obj) {
|
||||
$location = "translate.json[index $index]";
|
||||
if (!is_array($obj)) {
|
||||
$formatErrors[] = ['location' => $location, 'message' => '条目必须是对象'];
|
||||
continue;
|
||||
}
|
||||
[$entryFormatErrors, $entryRegexErrors] = validate_entry($obj, $location, false);
|
||||
$formatErrors = array_merge($formatErrors, $entryFormatErrors);
|
||||
$regexErrors = array_merge($regexErrors, $entryRegexErrors);
|
||||
if (!isset($obj['key']) || !is_string($obj['key'])) {
|
||||
continue;
|
||||
}
|
||||
$currentKey = $obj['key'];
|
||||
$originalKey = preg_replace(["/\(%T\d+\)/", "/\(%M\d+\)/"], ["(*)", "(**)"], $currentKey);
|
||||
$originalKey = normalize_key($currentKey);
|
||||
if (!in_array($originalKey, $originals)) {
|
||||
$redundants[$originalKey] = $obj;
|
||||
continue;
|
||||
}
|
||||
$translations[$originalKey] = $obj;
|
||||
if (preg_match_all('/\(%[TM]\d+\)/', $currentKey, $matches)) {
|
||||
foreach ($matches[0] as $match) {
|
||||
foreach ($obj as $k => $v) {
|
||||
if (empty($v)) {
|
||||
continue;
|
||||
}
|
||||
if (!str_contains($v, $match)) {
|
||||
$regrror[$originalKey] = ['key' => $currentKey, 'field' => $k, 'value' => $v, 'match' => $match];
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isset($translations[$originalKey])) {
|
||||
$formatErrors[] = [
|
||||
'location' => $location,
|
||||
'message' => "规范化后 key 重复:$originalKey",
|
||||
];
|
||||
continue;
|
||||
}
|
||||
$translations[$originalKey] = $obj;
|
||||
}
|
||||
return [$translations, $redundants, $regrror];
|
||||
return [$translations, $redundants, $regexErrors, $formatErrors];
|
||||
}
|
||||
|
||||
// ---- 公共:由 translate.json + originals 重新生成 public 文件 ----
|
||||
@ -127,7 +221,7 @@ function generate(array $generateds, array $translations): void
|
||||
|
||||
if ($cmd === 'diff') {
|
||||
[$originals, $generateds] = read_generateds();
|
||||
[$translations, $redundants, $regrror] = build_translations($originals);
|
||||
[$translations, $redundants, $regexErrors, $formatErrors] = build_translations($originals);
|
||||
|
||||
// 需要翻译的数据(对齐 translate.php 150-169:占位符按单一计数器编号)
|
||||
$needs = [];
|
||||
@ -153,14 +247,16 @@ if ($cmd === 'diff') {
|
||||
echo json_encode([
|
||||
'needsCount' => count($needsOut),
|
||||
'redundantCount' => count($redundants),
|
||||
'regexErrorCount' => count($regrror),
|
||||
'formatErrorCount' => count($formatErrors),
|
||||
'regexErrorCount' => count($regexErrors),
|
||||
'needs' => $needsOut,
|
||||
'redundants' => array_keys($redundants),
|
||||
'regexErrors' => array_values($regrror),
|
||||
'formatErrors' => array_values($formatErrors),
|
||||
'regexErrors' => array_values($regexErrors),
|
||||
], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . "\n";
|
||||
|
||||
if (count($regrror) > 0) {
|
||||
exit(2); // 已有数据占位符错乱,需先修复
|
||||
if (count($formatErrors) > 0 || count($regexErrors) > 0) {
|
||||
exit(2); // 已有数据格式或占位符错乱,需先修复
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
@ -172,9 +268,10 @@ if ($cmd === 'apply') {
|
||||
exit(1);
|
||||
}
|
||||
[$originals, $generateds] = read_generateds();
|
||||
[$translations, $redundants, $regrror] = build_translations($originals);
|
||||
if (count($regrror) > 0) {
|
||||
fwrite(STDERR, "translate.json 已有条目占位符错乱,请先修复再发版。\n");
|
||||
[$translations, $redundants, $regexErrors, $formatErrors] = build_translations($originals);
|
||||
if (count($formatErrors) > 0 || count($regexErrors) > 0) {
|
||||
print_validation_errors($formatErrors, $regexErrors);
|
||||
fwrite(STDERR, "translate.json 已有条目格式或占位符错误,请先修复再发版。\n");
|
||||
exit(2);
|
||||
}
|
||||
|
||||
@ -183,45 +280,49 @@ if ($cmd === 'apply') {
|
||||
fwrite(STDERR, "translated.json 必须是数组\n");
|
||||
exit(1);
|
||||
}
|
||||
$added = 0;
|
||||
foreach ($incoming as $raw) {
|
||||
foreach ($GLOBALS['LANG_FIELDS'] as $f) {
|
||||
if (!array_key_exists($f, $raw)) {
|
||||
fwrite(STDERR, "新翻译缺字段 \"$f\":" . json_encode($raw, JSON_UNESCAPED_UNICODE) . "\n");
|
||||
exit(1);
|
||||
}
|
||||
$originalSet = array_flip($originals);
|
||||
$incomingSeen = [];
|
||||
$itemsToAdd = [];
|
||||
foreach ($incoming as $index => $raw) {
|
||||
if (!is_array($raw)) {
|
||||
fwrite(STDERR, "新翻译 translated.json[index $index] 必须是对象\n");
|
||||
exit(1);
|
||||
}
|
||||
// 占位符完整性:key 里每个 (%T1)/(%M1) 必须出现在每个非空语言值里
|
||||
if (preg_match_all('/\(%[TM]\d+\)/', $raw['key'], $m)) {
|
||||
foreach ($m[0] as $match) {
|
||||
foreach ($GLOBALS['LANG_FIELDS'] as $f) {
|
||||
if ($f === 'key' || $f === 'zh') {
|
||||
continue;
|
||||
}
|
||||
if (empty($raw[$f])) {
|
||||
continue;
|
||||
}
|
||||
if (!str_contains($raw[$f], $match)) {
|
||||
fwrite(STDERR, "占位符 $match 在字段 \"$f\" 缺失:{$raw['key']}\n");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
[$incomingFormatErrors, $incomingRegexErrors] = validate_entry($raw, "translated.json[index $index]", true);
|
||||
if (count($incomingFormatErrors) > 0 || count($incomingRegexErrors) > 0) {
|
||||
print_validation_errors($incomingFormatErrors, $incomingRegexErrors);
|
||||
exit(1);
|
||||
}
|
||||
// 规范化:固定字段顺序 + zh 置空
|
||||
$item = [];
|
||||
foreach ($GLOBALS['LANG_FIELDS'] as $f) {
|
||||
$item[$f] = $f === 'zh' ? '' : $raw[$f];
|
||||
}
|
||||
$originalKey = preg_replace(["/\(%T\d+\)/", "/\(%M\d+\)/"], ["(*)", "(**)"], $item['key']);
|
||||
$originalKey = normalize_key($item['key']);
|
||||
if (!isset($originalSet[$originalKey])) {
|
||||
fwrite(STDERR, "新翻译 key 不在 original-web.txt/original-api.txt:{$item['key']}\n");
|
||||
exit(1);
|
||||
}
|
||||
if (isset($incomingSeen[$originalKey])) {
|
||||
fwrite(STDERR, "新翻译输入内部重复:translated.json[index {$incomingSeen[$originalKey]}] 与 translated.json[index $index] 规范化后均为「$originalKey」\n");
|
||||
exit(1);
|
||||
}
|
||||
if (isset($translations[$originalKey])) {
|
||||
fwrite(STDERR, "新翻译 key 已存在于 translate.json,非待补项或存在覆盖歧义:{$item['key']}(规范化:$originalKey)\n");
|
||||
exit(1);
|
||||
}
|
||||
$incomingSeen[$originalKey] = $index;
|
||||
$itemsToAdd[$originalKey] = $item;
|
||||
}
|
||||
|
||||
foreach ($itemsToAdd as $originalKey => $item) {
|
||||
$translations[$originalKey] = $item;
|
||||
$added++;
|
||||
}
|
||||
|
||||
// array_values:现有条目(去冗余)在前,新条目追加在后
|
||||
file_put_contents("translate.json", json_encode(array_values($translations), JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));
|
||||
echo json_encode([
|
||||
'added' => $added,
|
||||
'added' => count($itemsToAdd),
|
||||
'total' => count($translations),
|
||||
'droppedRedundant' => count($redundants),
|
||||
], JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT) . "\n";
|
||||
@ -230,7 +331,12 @@ if ($cmd === 'apply') {
|
||||
|
||||
if ($cmd === 'generate') {
|
||||
[$originals, $generateds] = read_generateds();
|
||||
[$translations] = build_translations($originals);
|
||||
[$translations, $redundants, $regexErrors, $formatErrors] = build_translations($originals);
|
||||
if (count($formatErrors) > 0 || count($regexErrors) > 0) {
|
||||
print_validation_errors($formatErrors, $regexErrors);
|
||||
fwrite(STDERR, "translate.json 存在格式或占位符错误,已停止生成。\n");
|
||||
exit(2);
|
||||
}
|
||||
generate($generateds, $translations);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
2
.github/workflows/tests.yml
vendored
2
.github/workflows/tests.yml
vendored
@ -36,10 +36,8 @@ jobs:
|
||||
- name: ESLint
|
||||
run: npm run lint
|
||||
|
||||
# 存量缺失文案 93 条(见 scripts/check-language.mjs 输出),清零后移除 continue-on-error 改为强制
|
||||
- name: Language Check
|
||||
run: npm run check:lang
|
||||
continue-on-error: true
|
||||
|
||||
phpunit:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
@ -1,10 +1,5 @@
|
||||
模版满足多种团队协作场景,同时支持自定义模版,满足团队个性化场景管理需求,可直观的查看项目的进展情况,团队协作更方便。
|
||||
2、若你是团队的所有者,请在删除您的帐号前转移所有权。例如该帐号所创建的项目(可将项目移交他人或删除项目)以及文件夹。
|
||||
汇集文档、电子表格、思维笔记等多种在线工具,汇聚企业知识资源于一处,支持多人实时协同编辑,让团队协作更便捷。
|
||||
多平台应用支持,打开客户端即可跟进项目任务进度, 同时让你在工作中每一个步骤都能拥有更高效愉悦的体验。
|
||||
1、您将无法查看该帐号内的任何信息,包括帐号信息、文件记录、聊天记录、项目信息、团队成员信息等。
|
||||
通过灵活的任务日历,轻松安排每一天的日程,把任务拆解到每天,让工作目标更清晰,时间分配更合理。
|
||||
针对项目和任务建立群组,工作问题可及时沟通,促进团队快速协作,提高团队工作效率。
|
||||
帐号删除后,该帐号将无法正常登录且无法恢复,帐号下的所有数据也将被删除。
|
||||
复杂:大于或等于6个字符,包含数字、字母大小写或者特殊字符。
|
||||
不会向忽略的邮箱地址发送邮件,可使用换行分割多个地址。
|
||||
@ -24,7 +19,6 @@
|
||||
开启后可以直接使用 LDAP 帐号密码登录
|
||||
必填:发送聊天内容前必须设置昵称。
|
||||
移除成员负责的任务将变成无负责人,
|
||||
首页底部:首页底部网站备案号等信息
|
||||
为确保帐号安全,请确认是本人操作
|
||||
修改邮箱和删除帐号需要邮箱验证码
|
||||
关闭签到功能再开启需要重新安装。
|
||||
@ -42,7 +36,6 @@
|
||||
+ 输入子任务,回车添加子任务
|
||||
4、请保证帐号未被暂停使用。
|
||||
只能设置单个状态为验收/测试
|
||||
以下是你当前的任务统计数据
|
||||
可通过此链接直接加入项目。
|
||||
项目不存在或不在成员列表内
|
||||
简单:大于或等于6个字符。
|
||||
@ -54,14 +47,12 @@
|
||||
任务列表不存在或已被删除
|
||||
密码错误,请输入正确密码
|
||||
开放:所有人都可以发言。
|
||||
强大易用的协同创作云文档
|
||||
注销前,请确认一下事项
|
||||
签到前后时间收到消息通知
|
||||
签到提醒对象:3天内有签到的成员(法定工作日)
|
||||
该状态下任务自动标记完成
|
||||
输入您的信息以创建帐户。
|
||||
仅支持Openwrt系统的路由器
|
||||
便捷易用的项目管理模板
|
||||
允许成员自己修改MAC地址
|
||||
可设置多个状态为进行中
|
||||
可通过此链接浏览文件。
|
||||
@ -70,7 +61,6 @@
|
||||
注意:离职操作不可逆!
|
||||
请输入正确的邮箱地址!
|
||||
项目负责人无法退出项目
|
||||
高效便捷的团队沟通工具
|
||||
以 http:// 或 https:// 开头
|
||||
请开启您PHP环境的openssl
|
||||
两次密码输入不一致!
|
||||
@ -90,17 +80,13 @@
|
||||
仅限项目负责人修改
|
||||
仅限项目负责人删除
|
||||
仅限项目负责人操作
|
||||
任务描述,回车创建
|
||||
你好,扫码确认登录
|
||||
你确定要登出系统吗?
|
||||
你确认领取任务吗?
|
||||
列表名称,回车创建
|
||||
同步修改子任务时间
|
||||
子任务不支持此功能
|
||||
最后在线于很久以前
|
||||
注意此操作不可逆!
|
||||
浏览图片空间的图片
|
||||
清晰直观的任务日历
|
||||
确认密码输入不一致
|
||||
请先修改登录密码!
|
||||
请填写正确的旧密码
|
||||
@ -108,7 +94,6 @@
|
||||
请输入正确的邀请码
|
||||
请输入正确的验证码
|
||||
请重新输入新密码!
|
||||
轻量级任务管理工具
|
||||
输入群名称(选填)
|
||||
电话长度至少6位!
|
||||
不支持复制文件夹
|
||||
@ -139,8 +124,6 @@
|
||||
超出文件大小限制
|
||||
输入您的电子邮件
|
||||
选择任务协助人员
|
||||
选择转发指定成员
|
||||
选择转发最近聊天
|
||||
邮箱、昵称、职位
|
||||
请输入会议频道ID
|
||||
第二次任务提醒
|
||||
@ -158,9 +141,7 @@
|
||||
帐号或密码错误
|
||||
我的待完成任务
|
||||
拖动到这里发送
|
||||
支持多平台应用
|
||||
文件格式不正确
|
||||
最后在线于刚刚
|
||||
最近打开的任务
|
||||
未保存计划时间
|
||||
正在上传文件...
|
||||
@ -263,14 +244,9 @@ ID、名称、描述...
|
||||
验证码已失效
|
||||
使用 SSO 登录
|
||||
PPT 演示文稿
|
||||
同步滚动:关
|
||||
同步滚动:开
|
||||
Excel 工作表
|
||||
html转markdown
|
||||
上传文件夹
|
||||
不是发送人
|
||||
今日待完成
|
||||
代码块主题
|
||||
任务不存在
|
||||
任务优先级
|
||||
任务已完成
|
||||
@ -296,7 +272,6 @@ html转markdown
|
||||
工作流设置
|
||||
已删除任务
|
||||
已完成任务
|
||||
已完成列表
|
||||
已归档任务
|
||||
开启工作流
|
||||
归档的任务
|
||||
@ -314,7 +289,6 @@ html转markdown
|
||||
最晚可延后
|
||||
服务器版本
|
||||
未完成任务
|
||||
未完成列表
|
||||
未开放注册
|
||||
未知的消息
|
||||
标记未完成
|
||||
@ -358,13 +332,13 @@ SMTP服务器
|
||||
职位/职称
|
||||
验收/测试
|
||||
(*) 超期
|
||||
未来 3 天内暂无到期任务
|
||||
未来 (*) 天内暂无到期任务
|
||||
暂无高优先级任务
|
||||
所有任务均已分配负责人
|
||||
当前筛选条件下暂无任务
|
||||
可以切换上方条件查看其他任务
|
||||
数据更新说明
|
||||
页面统计数据在 60 秒内复用,重点关注任务列表除外。
|
||||
页面统计数据在 (*) 秒内复用,重点关注任务列表除外。
|
||||
上次更新:(*)
|
||||
立即刷新
|
||||
刷新成功
|
||||
@ -407,14 +381,11 @@ SMTP服务器
|
||||
允许修改
|
||||
允许注册
|
||||
全员群组
|
||||
全屏查看
|
||||
全屏编辑
|
||||
全部文件
|
||||
全部禁言
|
||||
共享权限
|
||||
共享设置
|
||||
准备发布
|
||||
分屏显示
|
||||
创建时间
|
||||
创建群组
|
||||
创建项目
|
||||
@ -575,7 +546,6 @@ SMTP服务器
|
||||
紧凑经典
|
||||
经典天盘
|
||||
结束状态
|
||||
缩小查看
|
||||
群组设置
|
||||
聊天昵称
|
||||
聊天资料
|
||||
@ -643,7 +613,6 @@ LDAP 地址
|
||||
LDAP 端口
|
||||
MD编辑器
|
||||
Word 文档
|
||||
导出XLSX
|
||||
MAC地址
|
||||
扫一扫
|
||||
上个月
|
||||
@ -663,9 +632,6 @@ MAC地址
|
||||
到期后
|
||||
天空蓝
|
||||
子任务
|
||||
导出CSV
|
||||
导出TXT
|
||||
导出XLS
|
||||
已删除
|
||||
已取消
|
||||
已完成
|
||||
@ -901,20 +867,17 @@ Pro版
|
||||
(*)秒
|
||||
给
|
||||
(*)是一款轻量级的开源在线项目任务管理工具,提供各类文档协作工具、在线思维导图、在线流程图、项目管理、任务分发、即时IM,文件管理等工具。
|
||||
(*)负责的部门、项目、任务和文件将移交给交接人;同时退出所有群(如果是群主则转让给交接人)
|
||||
流转到【(*)】时,[任务负责人] 和 [项目管理员] 可以修改状态。
|
||||
文件(*)格式不正确,请上传(*)格式的图片。
|
||||
流转到【(*)】时添加状态负责人至任务负责人。
|
||||
每个文件夹里最多只能创建(*)个文件或文件夹
|
||||
文件(*)格式不正确,仅支持上传:(*)
|
||||
正在进行帐号【(*)】MAC地址修改。
|
||||
正在进行帐号【(*)】离职操作。
|
||||
正在进行帐号【(*)】部门修改。
|
||||
文件大小超限,最大限制:(*)KB
|
||||
职位/职称最多只能设置(*)个字
|
||||
任务描述最多只能设置(*)个字
|
||||
你确定要归档项目【(*)】吗?
|
||||
文件(*)太大,不能超过:(*)'
|
||||
文件名称最多只能设置(*)个字
|
||||
文件格式错误,限制类型:(*)
|
||||
项目介绍最多只能设置(*)个字
|
||||
@ -928,8 +891,6 @@ Pro版
|
||||
消息内容最大不能超过(*)字
|
||||
项目列表最多不能超过(*)个
|
||||
项目名称不可以少于(*)个字
|
||||
最多只能上传(*)张图片。
|
||||
最多只能选择(*)张图片。
|
||||
密码最多只能设置(*)位数
|
||||
密码设置不能小于(*)位数
|
||||
描述最多只能设置(*)个字
|
||||
@ -1059,8 +1020,6 @@ Pro版
|
||||
删除人员
|
||||
删除的任务
|
||||
你确定要还原删除吗?
|
||||
转换成markdown
|
||||
请输入html代码...
|
||||
请输入License...
|
||||
详细信息
|
||||
域名
|
||||
@ -1362,9 +1321,7 @@ APP 推送
|
||||
你确定取消待办吗?
|
||||
取消成功
|
||||
请等待打包完成
|
||||
选择一个项目查看更多任务
|
||||
首页
|
||||
无相关数据
|
||||
权限设置
|
||||
任务列权限
|
||||
添加列
|
||||
@ -1737,11 +1694,11 @@ WiFi签到延迟时长为±1分钟。
|
||||
注意:此操作不可恢复,部门下的成员将移至默认部门。
|
||||
维护中...
|
||||
|
||||
(*)评论了(*)的「(**)」审批
|
||||
抄送(*)提交的「(**)」记录
|
||||
(*)提交的「(**)」待你审批
|
||||
您发起的「(**)」已通过
|
||||
您发起的「(**)」被(*)拒绝
|
||||
(*)评论了(*)的「(*)」审批
|
||||
抄送(*)提交的「(*)」记录
|
||||
(*)提交的「(*)」待你审批
|
||||
您发起的「(*)」已通过
|
||||
您发起的「(*)」被(*)拒绝
|
||||
|
||||
翻译
|
||||
从不
|
||||
@ -2351,7 +2308,6 @@ AI 消息助手
|
||||
留空则不修改密码
|
||||
职位
|
||||
请输入电话号码
|
||||
正在编辑帐号【ID:(*)】的信息。
|
||||
编辑用户信息
|
||||
|
||||
AI任务分析
|
||||
@ -2568,7 +2524,7 @@ AI任务分析
|
||||
团队本周已完成 (*) 项
|
||||
查看任务
|
||||
涉及 (*) 人
|
||||
3 天内到期
|
||||
(*) 天内到期
|
||||
本周完成
|
||||
较上周
|
||||
与上周持平
|
||||
@ -2586,12 +2542,11 @@ AI任务分析
|
||||
全部显示完毕
|
||||
逾期 (*) 天
|
||||
逾期 (*) 小时
|
||||
夜深了,{username}
|
||||
早上好,{username}
|
||||
中午好,{username}
|
||||
下午好,{username}
|
||||
晚上好,{username}
|
||||
演示数据,接口对接后可打开任务详情
|
||||
夜深了,(*)
|
||||
早上好,(*)
|
||||
中午好,(*)
|
||||
下午好,(*)
|
||||
晚上好,(*)
|
||||
服务器时间
|
||||
暂无已超期任务
|
||||
暂无今日到期任务
|
||||
@ -2600,7 +2555,6 @@ AI任务分析
|
||||
没有超期任务,保持住
|
||||
今天只有这一项,处理完就轻松了
|
||||
数量较多,仅显示最近 (*) 项,展开其余 (*) 项
|
||||
太棒了,当前没有需要处理的任务
|
||||
我的部门
|
||||
待开始
|
||||
暂无待开始任务
|
||||
@ -2620,3 +2574,87 @@ AI任务分析
|
||||
开启后在项目列表中显示额外的只读项目
|
||||
选择团队范围
|
||||
在项目列表中启用
|
||||
+(*)位
|
||||
(*)条回复
|
||||
AgoraIO 声网
|
||||
会话中断
|
||||
确定要清空所有历史会话吗?
|
||||
新窗口打开
|
||||
组件加载失败!
|
||||
没有更新描述。
|
||||
已全选
|
||||
已选部分
|
||||
你的姓名
|
||||
请输入你的姓名
|
||||
会议中
|
||||
未命名应用
|
||||
应用 ID
|
||||
应用名称
|
||||
菜单标题
|
||||
菜单位置
|
||||
应用中心 - 常用
|
||||
应用中心 - 管理
|
||||
主导航
|
||||
可见范围
|
||||
仅管理员
|
||||
图标地址
|
||||
菜单 URL
|
||||
背景颜色
|
||||
保持激活状态
|
||||
自动暗黑模式
|
||||
沉浸式
|
||||
透明背景
|
||||
禁用作用域样式
|
||||
可能要发的照片
|
||||
其他任务
|
||||
点击查看
|
||||
处理
|
||||
没有符合条件的数据
|
||||
正常
|
||||
暂无介绍
|
||||
关联子任务
|
||||
最多只能选择(*)个标签
|
||||
来源
|
||||
未知
|
||||
分享时间
|
||||
分享人
|
||||
标题
|
||||
任务状态
|
||||
已还原
|
||||
下个周期
|
||||
每
|
||||
LDAP 用户禁止修改邮箱
|
||||
共(*)个
|
||||
标签名称最多只能设置(*)个字
|
||||
添加失败
|
||||
未开启通知权限
|
||||
个
|
||||
使用端到端加密传输数据。
|
||||
删除前,请确认以下事项:
|
||||
已清楚风险,确定删除
|
||||
只能输入字母或数字
|
||||
授权
|
||||
不支持单独查看此消息
|
||||
报告详情
|
||||
验证邮箱
|
||||
您的邮箱已通过验证
|
||||
今后您可以通过此邮箱重置您的帐号密码
|
||||
链接已过期,已重新发送
|
||||
请设置昵称
|
||||
请设置联系电话
|
||||
文件 (*) 上传失败 (*)
|
||||
文件 (*) 格式不正确,请上传 jpg、jpeg、webp、gif、png 格式的图片。
|
||||
文件 (*) 太大,不能超过:(*)
|
||||
最多只能上传 (*) 张图片。
|
||||
最多只能选择 (*) 张图片。
|
||||
文件 (*) 上传失败,(*)
|
||||
文件 (*) 格式不正确,仅支持上传:(*)
|
||||
很久以前
|
||||
@我的消息
|
||||
确定要删除记录"(*)"吗?
|
||||
添加(*)
|
||||
共(*)个文件,仅显示最新50个
|
||||
正在进行帐号【ID:(*), (*)】离职操作。
|
||||
(*) 负责的部门、项目、任务和文件将移交给交接人;同时退出所有群(如果是群主则转让给交接人)
|
||||
正在编辑帐号【ID:(*), (*)】的信息。
|
||||
打包下载(*)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
2
public/language/web/de.js
vendored
2
public/language/web/de.js
vendored
File diff suppressed because one or more lines are too long
2
public/language/web/en.js
vendored
2
public/language/web/en.js
vendored
File diff suppressed because one or more lines are too long
2
public/language/web/fr.js
vendored
2
public/language/web/fr.js
vendored
File diff suppressed because one or more lines are too long
2
public/language/web/id.js
vendored
2
public/language/web/id.js
vendored
File diff suppressed because one or more lines are too long
2
public/language/web/ja.js
vendored
2
public/language/web/ja.js
vendored
File diff suppressed because one or more lines are too long
2
public/language/web/key.js
vendored
2
public/language/web/key.js
vendored
File diff suppressed because one or more lines are too long
2
public/language/web/ko.js
vendored
2
public/language/web/ko.js
vendored
File diff suppressed because one or more lines are too long
2
public/language/web/ru.js
vendored
2
public/language/web/ru.js
vendored
File diff suppressed because one or more lines are too long
2
public/language/web/zh-CHT.js
vendored
2
public/language/web/zh-CHT.js
vendored
File diff suppressed because one or more lines are too long
2
public/language/web/zh.js
vendored
2
public/language/web/zh.js
vendored
File diff suppressed because one or more lines are too long
@ -20,7 +20,7 @@ negative:
|
||||
- 语言切换只影响当前账号,不会改其他成员
|
||||
- 不影响其他用户给你发的消息(消息不会自动翻译,要单独用「消息翻译」功能)
|
||||
- 某些插件 / 微应用可能未提供完整翻译,会回退到中文 / 英文
|
||||
last_verified: v1.7.90
|
||||
last_verified: v1.8.69
|
||||
---
|
||||
|
||||
# 切换界面语言
|
||||
@ -33,7 +33,7 @@ last_verified: v1.7.90
|
||||
|
||||
## 支持的语言
|
||||
|
||||
由 `resources/assets/js/language/` 下文件清单决定,常见:
|
||||
由 `resources/assets/js/i18n/` 下文件清单决定,常见:
|
||||
|
||||
- 简体中文(zh)
|
||||
- 繁体中文(zh-CHT)
|
||||
|
||||
@ -104,7 +104,7 @@ import {mapState} from "vuex";
|
||||
import emitter from "./store/events";
|
||||
import AIAssistant from "./components/AIAssistant";
|
||||
import UserDetail from "./pages/manage/components/UserDetail.vue";
|
||||
import {languageName} from "./language";
|
||||
import {languageName} from "./i18n";
|
||||
|
||||
export default {
|
||||
mixins: [ctrlPressed],
|
||||
|
||||
2
resources/assets/js/app.js
vendored
2
resources/assets/js/app.js
vendored
@ -4,7 +4,7 @@ const isSoftware = isElectron || isEEUIApp;
|
||||
|
||||
document.getElementById("app")?.setAttribute("data-preload", "false");
|
||||
|
||||
import {languageName, switchLanguage as $L} from "./language";
|
||||
import {languageName, switchLanguage as $L} from "./i18n";
|
||||
import {isLocalHost} from "./components/Replace/utils";
|
||||
|
||||
import './functions/common'
|
||||
|
||||
@ -280,7 +280,7 @@ import FloatButton from "./float-button.vue";
|
||||
import AssistantModal from "./modal.vue";
|
||||
import PromptImage from "./prompt-image.vue";
|
||||
import {buildWeakPrompt, renderWeakPromptText} from "./page-context";
|
||||
import {getLanguage} from "../../language";
|
||||
import {getLanguage} from "../../i18n";
|
||||
import {getWelcomePrompts} from "./welcome-prompts";
|
||||
|
||||
export default {
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
* 提示内容基于 DooTask MCP 工具的实际能力设计
|
||||
*/
|
||||
|
||||
import {languageName} from "../../language";
|
||||
import {languageName} from "../../i18n";
|
||||
|
||||
// SVG 图标定义
|
||||
const SVG_ICONS = {
|
||||
|
||||
@ -37,7 +37,7 @@
|
||||
<script>
|
||||
import {mapState} from "vuex";
|
||||
import IFrame from "../pages/manage/components/IFrame";
|
||||
import {languageName} from "../language";
|
||||
import {languageName} from "../i18n";
|
||||
|
||||
export default {
|
||||
name: "Drawio",
|
||||
|
||||
@ -212,7 +212,7 @@ export default {
|
||||
if (type == 'day') {
|
||||
return date.date();
|
||||
} else if (type == 'week') {
|
||||
return this.$L(`星期${'日一二三四五六'.charAt(date.day())}`);
|
||||
return this.$L(['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'][date.day()]);
|
||||
} else {
|
||||
return date;
|
||||
}
|
||||
|
||||
@ -293,7 +293,7 @@ export default {
|
||||
} else {
|
||||
$A.noticeWarning({
|
||||
title: this.$L('上传失败'),
|
||||
desc: this.$L('文件 ' + file.name + ' 上传失败 ' + res.msg),
|
||||
desc: this.$L('文件 (*) 上传失败 (*)', file.name, res.msg),
|
||||
});
|
||||
this.$refs.upload.fileList.pop();
|
||||
}
|
||||
@ -307,14 +307,14 @@ export default {
|
||||
//上传类型错误
|
||||
$A.noticeWarning({
|
||||
title: this.$L('文件格式不正确'),
|
||||
desc: this.$L('文件 ' + file.name + ' 格式不正确,请上传 jpg、jpeg、webp、gif、png 格式的图片。')
|
||||
desc: this.$L('文件 (*) 格式不正确,请上传 jpg、jpeg、webp、gif、png 格式的图片。', file.name)
|
||||
});
|
||||
},
|
||||
handleMaxSize(file) {
|
||||
//上传大小错误
|
||||
$A.noticeWarning({
|
||||
title: this.$L('超出文件大小限制'),
|
||||
desc: this.$L('文件 ' + file.name + ' 太大,不能超过:' + $A.bytesToSize(this.maxImageSize * 1024))
|
||||
desc: this.$L('文件 (*) 太大,不能超过:(*)', file.name, $A.bytesToSize(this.maxImageSize * 1024))
|
||||
});
|
||||
},
|
||||
handleBeforeUpload(file) {
|
||||
@ -325,7 +325,7 @@ export default {
|
||||
check = this.uploadList.length < this.maxNum;
|
||||
}
|
||||
if (!check) {
|
||||
$A.noticeWarning(this.$L('最多只能上传 ' + this.maxNum + ' 张图片。'));
|
||||
$A.noticeWarning(this.$L('最多只能上传 (*) 张图片。', this.maxNum));
|
||||
return false;
|
||||
}
|
||||
// ≥ 10MB 走分片(iview max-size 拦在前,需调用方放大 maxSize 才能进到这里)
|
||||
@ -370,7 +370,7 @@ export default {
|
||||
} catch (err) {
|
||||
$A.noticeWarning({
|
||||
title: this.$L('上传失败'),
|
||||
desc: this.$L('文件 ' + rawFile.name + ' 上传失败 ' + ((err && err.message) || '')),
|
||||
desc: this.$L('文件 (*) 上传失败 (*)', rawFile.name, (err && err.message) || ''),
|
||||
});
|
||||
const idx = this.$refs.upload.fileList.indexOf(item);
|
||||
if (idx > -1) this.$refs.upload.fileList.splice(idx, 1);
|
||||
@ -452,7 +452,7 @@ export default {
|
||||
}
|
||||
let check = this.uploadList.length < this.maxNum;
|
||||
if (!check) {
|
||||
$A.noticeWarning(this.$L('最多只能选择 ' + this.maxNum + ' 张图片。'));
|
||||
$A.noticeWarning(this.$L('最多只能选择 (*) 张图片。', this.maxNum));
|
||||
return;
|
||||
}
|
||||
item.active = true;
|
||||
|
||||
@ -153,7 +153,7 @@ import {DatePicker} from 'view-design-hi';
|
||||
import microApp from '@micro-zoe/micro-app'
|
||||
import DialogWrapper from '../../pages/manage/components/DialogWrapper.vue'
|
||||
import UserSelect from "../UserSelect.vue";
|
||||
import {languageList, languageName} from "../../language";
|
||||
import {languageList, languageName} from "../../i18n";
|
||||
import emitter from "../../store/events";
|
||||
import TransferDom from "../../directives/transfer-dom";
|
||||
import store from "../../store";
|
||||
|
||||
@ -58,7 +58,7 @@
|
||||
</style>
|
||||
<script>
|
||||
import {mapState} from "vuex";
|
||||
import {languageName} from "../language";
|
||||
import {languageName} from "../i18n";
|
||||
|
||||
export default {
|
||||
name: "OnlyOffice",
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<script>
|
||||
import {mapState} from "vuex";
|
||||
import PreviewImage from "./index";
|
||||
import {languageName} from "../../language";
|
||||
import {languageName} from "../../i18n";
|
||||
|
||||
export default {
|
||||
name: 'PreviewImageState',
|
||||
|
||||
@ -68,7 +68,7 @@
|
||||
import tinymce from 'tinymce/tinymce';
|
||||
import ImgUpload from "./ImgUpload";
|
||||
import {mapState} from "vuex";
|
||||
import {languageName} from "../language";
|
||||
import {languageName} from "../i18n";
|
||||
import {chunkedUpload, CHUNK_THRESHOLD} from "../store/chunkedUpload";
|
||||
|
||||
const windowTouch = "ontouchend" in document
|
||||
@ -661,7 +661,7 @@ export default {
|
||||
} else {
|
||||
$A.noticeWarning({
|
||||
title: this.$L('上传失败'),
|
||||
desc: this.$L('文件 ' + file.name + ' 上传失败,' + res.msg)
|
||||
desc: this.$L('文件 (*) 上传失败,(*)', file.name, res.msg)
|
||||
});
|
||||
}
|
||||
},
|
||||
@ -675,7 +675,7 @@ export default {
|
||||
//上传类型错误
|
||||
$A.noticeWarning({
|
||||
title: this.$L('文件格式不正确'),
|
||||
desc: this.$L('文件 ' + file.name + ' 格式不正确,仅支持上传:' + this.uploadFormat.join(','))
|
||||
desc: this.$L('文件 (*) 格式不正确,仅支持上传:(*)', file.name, this.uploadFormat.join(','))
|
||||
});
|
||||
},
|
||||
|
||||
@ -683,7 +683,7 @@ export default {
|
||||
//上传大小错误
|
||||
$A.noticeWarning({
|
||||
title: this.$L('超出文件大小限制'),
|
||||
desc: this.$L('文件 ' + file.name + ' 太大,不能超过:' + $A.bytesToSize(this.maxSize * 1024))
|
||||
desc: this.$L('文件 (*) 太大,不能超过:(*)', file.name, $A.bytesToSize(this.maxSize * 1024))
|
||||
});
|
||||
},
|
||||
|
||||
@ -708,7 +708,7 @@ export default {
|
||||
} catch (err) {
|
||||
$A.noticeWarning({
|
||||
title: this.$L('上传失败'),
|
||||
desc: this.$L('文件 ' + rawFile.name + ' 上传失败,' + ((err && err.message) || '')),
|
||||
desc: this.$L('文件 (*) 上传失败,(*)', rawFile.name, (err && err.message) || ''),
|
||||
});
|
||||
} finally {
|
||||
this.uploadIng--;
|
||||
|
||||
@ -92,26 +92,26 @@ export default {
|
||||
const now = $A.daytz()
|
||||
const line = $A.dayjs(this.user.line_at)
|
||||
const seconds = now.unix() - line.unix()
|
||||
let stats = '最后在线于很久以前';
|
||||
let stats = this.$L('最后在线于(*)', this.$L('很久以前'));
|
||||
if (seconds < 60) {
|
||||
stats = `最后在线于刚刚`
|
||||
stats = this.$L('最后在线于(*)', this.$L('刚刚'))
|
||||
} else if (seconds < 3600) {
|
||||
stats = `最后在线于 ${Math.floor(seconds / 60)} 分钟前`
|
||||
stats = this.$L('最后在线于(*)分钟前', Math.floor(seconds / 60))
|
||||
} else if (seconds < 3600 * 6) {
|
||||
stats = `最后在线于 ${Math.floor(seconds / 3600)} 小时前`
|
||||
stats = this.$L('最后在线于(*)小时前', Math.floor(seconds / 3600))
|
||||
} else {
|
||||
const nowYmd = now.format('YYYY-MM-DD')
|
||||
const lineYmd = line.format('YYYY-MM-DD')
|
||||
const lineHi = line.format('HH:mm')
|
||||
if (nowYmd === lineYmd) {
|
||||
stats = `最后在线于今天 ${lineHi}`
|
||||
stats = this.$L('最后在线于今天(*)', lineHi)
|
||||
} else if (now.clone().subtract(1, 'day').format('YYYY-MM-DD') === lineYmd) {
|
||||
stats = `最后在线于昨天 ${lineHi}`
|
||||
stats = this.$L('最后在线于昨天(*)', lineHi)
|
||||
} else if (seconds < 3600 * 24 * 365) {
|
||||
stats = `最后在线于 ${lineYmd}`
|
||||
stats = this.$L('最后在线于(*)', lineYmd)
|
||||
}
|
||||
}
|
||||
this.$emit('update:online', this.$L(stats))
|
||||
this.$emit('update:online', stats)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -77,7 +77,7 @@ import '@kangc/v-md-editor/lib/theme/style/vuepress.css';
|
||||
import Prism from 'prismjs';
|
||||
|
||||
// Language
|
||||
import {languageName} from "../../../language";
|
||||
import {languageName} from "../../../i18n";
|
||||
import zhCN from '@kangc/v-md-editor/lib/lang/zh-CN';
|
||||
import enUS from '@kangc/v-md-editor/lib/lang/en-US';
|
||||
|
||||
|
||||
@ -20,7 +20,7 @@ import '@kangc/v-md-editor/lib/theme/style/vuepress.css';
|
||||
import Prism from 'prismjs';
|
||||
|
||||
// Language
|
||||
import {languageName} from "../../../language";
|
||||
import {languageName} from "../../../i18n";
|
||||
import zhCN from '@kangc/v-md-editor/lib/lang/zh-CN';
|
||||
import enUS from '@kangc/v-md-editor/lib/lang/en-US';
|
||||
|
||||
|
||||
2
resources/assets/js/functions/eeui.js
vendored
2
resources/assets/js/functions/eeui.js
vendored
@ -1,7 +1,7 @@
|
||||
/**
|
||||
* EEUI App 专用
|
||||
*/
|
||||
import {languageName} from "../language";
|
||||
import {languageName} from "../i18n";
|
||||
|
||||
(function (window) {
|
||||
const $ = window.$A;
|
||||
|
||||
6
resources/assets/js/functions/web.js
vendored
6
resources/assets/js/functions/web.js
vendored
@ -165,17 +165,17 @@ import {convertLocalResourcePath} from "../components/Replace/utils";
|
||||
return [startSecond, $A.daytz().endOf('month').toDate()];
|
||||
}
|
||||
}, {
|
||||
text: $A.L('3天'),
|
||||
text: $A.L('(*)天', 3),
|
||||
value() {
|
||||
return [startSecond, $A.daytz().add(2, 'day').endOf('day').toDate()];
|
||||
}
|
||||
}, {
|
||||
text: $A.L('5天'),
|
||||
text: $A.L('(*)天', 5),
|
||||
value() {
|
||||
return [startSecond, $A.daytz().add(4, 'day').endOf('day').toDate()];
|
||||
}
|
||||
}, {
|
||||
text: $A.L('7天'),
|
||||
text: $A.L('(*)天', 7),
|
||||
value() {
|
||||
return [startSecond, $A.daytz().add(6, 'day').endOf('day').toDate()];
|
||||
}
|
||||
|
||||
@ -3,7 +3,7 @@ const utils = require('./utils')
|
||||
const languageList = utils.languageList
|
||||
const languageName = utils.getLanguage()
|
||||
const languageCache = new Map();
|
||||
const languageRegex = [];
|
||||
const languageTemplateCache = new Map();
|
||||
|
||||
if (typeof window.LANGUAGE_DATA === "undefined") {
|
||||
window.LANGUAGE_DATA = {}
|
||||
@ -21,25 +21,21 @@ function initLanguage() {
|
||||
//
|
||||
keys.forEach((key, index) => {
|
||||
if (/\(%[TM]\d+\)/.test(key)) {
|
||||
// 处理复杂的键值
|
||||
const _m = {};
|
||||
const translation = {
|
||||
key: new RegExp("^" + utils.replaceEscape(key) + "$"),
|
||||
}
|
||||
// 缓存参数化键值
|
||||
const template = utils.normalizeArgumentsLanguage(key)
|
||||
const translateArguments = new Set();
|
||||
key.replace(/\(%M(\d+)\)/g, (_, index) => {
|
||||
translateArguments.add(index)
|
||||
})
|
||||
for (let language in window.LANGUAGE_DATA) {
|
||||
if (typeof languageList[language] === "undefined") {
|
||||
continue
|
||||
}
|
||||
translation[language] = window.LANGUAGE_DATA[language][index]
|
||||
?.replace(/\(%([TM])(\d+)\)/g, function (_, type, index) {
|
||||
if (type === 'M') {
|
||||
_m[index] = index;
|
||||
}
|
||||
return "$" + index;
|
||||
});
|
||||
languageTemplateCache.set(`${template}-${language}`, {
|
||||
text: window.LANGUAGE_DATA[language][index],
|
||||
translateArguments,
|
||||
});
|
||||
}
|
||||
translation._m = Object.keys(_m);
|
||||
languageRegex.push(translation)
|
||||
} else {
|
||||
// 缓存简单的键值
|
||||
for (let language in window.LANGUAGE_DATA) {
|
||||
@ -122,39 +118,31 @@ function getLanguage() {
|
||||
* @returns {string|*}
|
||||
*/
|
||||
function switchLanguage(inputString) {
|
||||
if (typeof arguments[1] !== "undefined") {
|
||||
inputString = utils.replaceArgumentsLanguage(inputString, arguments)
|
||||
}
|
||||
if (typeof inputString !== "string" || !inputString) {
|
||||
return inputString
|
||||
}
|
||||
|
||||
if (arguments.length > 1) {
|
||||
const templateKey = `${inputString}-${languageName}`;
|
||||
if (languageTemplateCache.has(templateKey)) {
|
||||
const {text, translateArguments} = languageTemplateCache.get(templateKey);
|
||||
if (!text) {
|
||||
return utils.replaceArgumentsLanguage(inputString, arguments);
|
||||
}
|
||||
return text.replace(/\(%[TM](\d+)\)/g, (_, index) => {
|
||||
const value = utils.getArgumentLanguage(arguments[index]);
|
||||
return translateArguments.has(index) ? switchLanguage(String(value)) : value;
|
||||
});
|
||||
}
|
||||
inputString = utils.replaceArgumentsLanguage(inputString, arguments)
|
||||
}
|
||||
|
||||
// 读取缓存
|
||||
const cacheKey = `${inputString}-${languageName}`;
|
||||
if (languageCache.has(cacheKey)) {
|
||||
return languageCache.get(cacheKey);
|
||||
}
|
||||
|
||||
// 正则匹配
|
||||
for (const translation of languageRegex) {
|
||||
const { key, _m } = translation;
|
||||
const match = key.exec(inputString);
|
||||
if (match) {
|
||||
if (translation[languageName]) {
|
||||
const result = translation[languageName].replace(/\$(\d+)/g, (_, index) => {
|
||||
if (_m.includes(index)) {
|
||||
return switchLanguage(match[index]);
|
||||
}
|
||||
return match[index] || '';
|
||||
});
|
||||
languageCache.set(cacheKey, result);
|
||||
return result;
|
||||
}
|
||||
languageCache.set(cacheKey, inputString);
|
||||
return inputString;
|
||||
}
|
||||
}
|
||||
|
||||
// 开发模式下,未翻译的文本自动添加到语言文件
|
||||
if (window.systemInfo.debug === "yes") {
|
||||
setTimeout(_ => {
|
||||
@ -22,30 +22,28 @@ export default {
|
||||
*/
|
||||
replaceArgumentsLanguage(text, objects) {
|
||||
let j = 1;
|
||||
while (text.indexOf("(*)") !== -1) {
|
||||
if (typeof objects[j] === "object") {
|
||||
text = text.replace("(*)", "");
|
||||
} else {
|
||||
text = text.replace("(*)", objects[j]);
|
||||
}
|
||||
j++;
|
||||
}
|
||||
return text;
|
||||
return text.replace(/\(\*\)/g, () => this.getArgumentLanguage(objects[j++]));
|
||||
},
|
||||
|
||||
/**
|
||||
* 译文转义
|
||||
* @param val
|
||||
* 获取语言参数
|
||||
* @param value
|
||||
* @returns {string|*}
|
||||
*/
|
||||
replaceEscape(val) {
|
||||
if (!val || val == '') {
|
||||
getArgumentLanguage(value) {
|
||||
if (value === null || typeof value === "undefined" || typeof value === "object") {
|
||||
return '';
|
||||
}
|
||||
return val
|
||||
.replace(/\(%[TM]\d+\)/g, "~:%%:~")
|
||||
.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&')
|
||||
.replace(/~:%%:~/g, '(.*?)');
|
||||
return value;
|
||||
},
|
||||
|
||||
/**
|
||||
* 规范化参数化语言键
|
||||
* @param text
|
||||
* @returns {string}
|
||||
*/
|
||||
normalizeArgumentsLanguage(text) {
|
||||
return text.replace(/\(%[TM]\d+\)/g, "(*)");
|
||||
},
|
||||
|
||||
/**
|
||||
@ -166,7 +166,7 @@
|
||||
|
||||
<script>
|
||||
import {mapState} from "vuex";
|
||||
import {languageList, languageName, setLanguage} from "../language";
|
||||
import {languageList, languageName, setLanguage} from "../i18n";
|
||||
import VueQrcode from "@chenfengyuan/vue-qrcode";
|
||||
import emitter from "../store/events";
|
||||
|
||||
@ -261,12 +261,12 @@ export default {
|
||||
subTitle() {
|
||||
const title = window.systemInfo.title || "DooTask";
|
||||
if (this.loginMode == 'qrcode') {
|
||||
return this.$L(`请使用${title}移动端扫描二维码。`)
|
||||
return this.$L('请使用(*)移动端扫描二维码。', title)
|
||||
}
|
||||
if (this.loginType=='reg') {
|
||||
return this.$L(`输入您的信息以创建帐户。`)
|
||||
return this.$L('输入您的信息以创建帐户。')
|
||||
}
|
||||
return this.$L(`输入您的凭证以访问您的帐户。`)
|
||||
return this.$L('输入您的凭证以访问您的帐户。')
|
||||
},
|
||||
|
||||
loginText() {
|
||||
|
||||
@ -262,7 +262,7 @@
|
||||
<Icon v-else type="ios-search" />
|
||||
</div>
|
||||
<Form class="search-form" action="javascript:void(0)" @submit.native.prevent="$A.eeuiAppKeyboardHide">
|
||||
<Input type="search" v-model="projectKeyValue" :placeholder="$L(`共${projectTotal || cacheProjects.length}个项目,搜索...`)" clearable/>
|
||||
<Input type="search" v-model="projectKeyValue" :placeholder="$L('共(*)个项目,搜索...', projectTotal || cacheProjects.length)" clearable/>
|
||||
</Form>
|
||||
</div>
|
||||
<ButtonGroup class="manage-box-new-group">
|
||||
@ -489,7 +489,7 @@ import notificationKoro from "notification-koro1";
|
||||
import emitter from "../store/events";
|
||||
import SearchBox from "../components/SearchBox.vue";
|
||||
import transformEmojiToHtml from "../utils/emoji";
|
||||
import {languageName} from "../language";
|
||||
import {languageName} from "../i18n";
|
||||
import {AINormalizeJsonContent, PROJECT_AI_SYSTEM_PROMPT, withLanguagePreferencePrompt} from "../utils/ai";
|
||||
import Draggable from 'vuedraggable'
|
||||
import DepartmentOwnerView from "./manage/components/DepartmentOwnerView.vue";
|
||||
@ -535,7 +535,7 @@ export default {
|
||||
addRule: {
|
||||
name: [
|
||||
{ required: true, message: this.$L('请填写项目名称!'), trigger: 'change' },
|
||||
{ type: 'string', min: 2, message: this.$L('项目名称至少2个字!'), trigger: 'change' }
|
||||
{ type: 'string', min: 2, message: this.$L('项目名称至少(*)个字!', 2), trigger: 'change' }
|
||||
]
|
||||
},
|
||||
|
||||
|
||||
@ -271,7 +271,7 @@
|
||||
:title="$L(mybotModifyData.id > 0 ? '修改机器人' : '添加机器人')"
|
||||
:mask-closable="false">
|
||||
<Form :model="mybotModifyData" v-bind="formOptions" @submit.native.prevent>
|
||||
<Alert v-if="mybotModifyData.system_name" type="error" style="margin-bottom:18px">{{ $L(`正在修改系统机器人:${mybotModifyData.system_name}`) }}</Alert>
|
||||
<Alert v-if="mybotModifyData.system_name" type="error" style="margin-bottom:18px">{{ $L('正在修改系统机器人:(*)', mybotModifyData.system_name) }}</Alert>
|
||||
<FormItem prop="avatar" :label="$L('头像')">
|
||||
<ImgUpload v-model="mybotModifyData.avatar" :num="1" :width="512" :height="512" whcut="cover"/>
|
||||
</FormItem>
|
||||
@ -396,7 +396,7 @@
|
||||
:title="$L('扫码登录')"
|
||||
:mask-closable="false">
|
||||
<div class="mobile-scan-login-box">
|
||||
<div class="mobile-scan-login-title">{{ $L(`你好,扫码确认登录`) }}</div>
|
||||
<div class="mobile-scan-login-title">{{ $L('你好,扫码确认登录') }}</div>
|
||||
<div class="mobile-scan-login-subtitle">「{{ $L('为确保帐号安全,请确认是本人操作') }}」</div>
|
||||
</div>
|
||||
<div slot="footer" class="adaption">
|
||||
|
||||
@ -50,7 +50,7 @@ import 'tui-calendar-hi/toastui-calendar.css';
|
||||
import Calendar from "./components/Calendar";
|
||||
import {theme} from './components/Calendar/theme';
|
||||
import emitter from "../../store/events";
|
||||
import {addLanguage} from "../../language";
|
||||
import {addLanguage} from "../../i18n";
|
||||
import {mapGetters, mapState} from "vuex";
|
||||
|
||||
export default {
|
||||
@ -95,15 +95,7 @@ export default {
|
||||
{"key": "{五}", "zh": "五", "general": "Fri"},
|
||||
{"key": "{六}", "zh": "六", "general": "Sat"},
|
||||
]);
|
||||
const dayNames = [
|
||||
this.$L('{日}'),
|
||||
this.$L('{一}'),
|
||||
this.$L('{二}'),
|
||||
this.$L('{三}'),
|
||||
this.$L('{四}'),
|
||||
this.$L('{五}'),
|
||||
this.$L('{六}')
|
||||
];
|
||||
const dayNames = ['{日}', '{一}', '{二}', '{三}', '{四}', '{五}', '{六}'].map(day => this.$L(day));
|
||||
this.options.week.dayNames = dayNames;
|
||||
this.options.month.dayNames = dayNames;
|
||||
this.options.view = this.$store.state.cacheCalendarView || this.options.view;
|
||||
|
||||
@ -340,7 +340,7 @@ import TransferDom from "../../../../directives/transfer-dom";
|
||||
import clickoutside from "../../../../directives/clickoutside";
|
||||
import longpress from "../../../../directives/longpress";
|
||||
import {inputLoadAdd, inputLoadIsLast, inputLoadRemove} from "./one";
|
||||
import {languageList, languageName} from "../../../../language";
|
||||
import {languageList, languageName} from "../../../../i18n";
|
||||
import {isMarkdownFormat, MarkdownConver} from "../../../../utils/markdown";
|
||||
import {cutText, extractPlainText} from "../../../../utils/text";
|
||||
import {MESSAGE_AI_SYSTEM_PROMPT, withLanguagePreferencePrompt} from "../../../../utils/ai";
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
<Form ref="export" :model="formData" v-bind="formOptions" @submit.native.prevent>
|
||||
<FormItem :label="$L('导出成员')">
|
||||
<UserSelect v-model="formData.userid" :multiple-max="100" avatar-name show-disable :title="$L('请选择成员')"/>
|
||||
<div class="form-tip">{{$L('每次最多选择导出100个成员')}}</div>
|
||||
<div class="form-tip">{{$L('每次最多选择导出(*)个成员', 100)}}</div>
|
||||
</FormItem>
|
||||
<FormItem :label="$L('签到日期')">
|
||||
<DatePicker
|
||||
|
||||
@ -27,7 +27,7 @@
|
||||
<div class="dialog-info">
|
||||
<div class="dialog-name" v-html="transformEmojiToHtml(dialog.name)"></div>
|
||||
<div class="dialog-meta">
|
||||
<span class="member-count">{{$L('(*)人', dialog.people || 0)}}</span>
|
||||
<span class="member-count">{{$L('(*) 人', dialog.people || 0)}}</span>
|
||||
<span v-if="dialog.last_at" class="last-time">{{$A.timeFormat(dialog.last_at)}}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
<div class="card-link link-red">{{$L('查看任务')}} →</div>
|
||||
</li>
|
||||
<li @click="onBlock('soon')">
|
||||
<div class="card-label">{{$L('3 天内到期')}}</div>
|
||||
<div class="card-label">{{$L('(*) 天内到期', 3)}}</div>
|
||||
<div class="card-data">
|
||||
<span class="card-num num-orange">{{blocks.due_soon || 0}}</span>
|
||||
<span class="card-sub">{{$L('项')}}</span>
|
||||
@ -302,7 +302,7 @@ export default {
|
||||
chips({blocks, highPriorityChip}) {
|
||||
return [
|
||||
{type: 'overdue', label: this.$L('已超期'), num: blocks.overdue || 0},
|
||||
{type: 'soon', label: this.$L('3 天内到期'), num: blocks.due_soon || 0},
|
||||
{type: 'soon', label: this.$L('(*) 天内到期', 3), num: blocks.due_soon || 0},
|
||||
{type: 'hi', label: highPriorityChip.label, num: highPriorityChip.num},
|
||||
{type: 'noowner', label: this.$L('未分配负责人'), num: blocks.no_owner || 0},
|
||||
]
|
||||
@ -341,7 +341,7 @@ export default {
|
||||
case 'overdue':
|
||||
return this.$L('暂无已超期任务')
|
||||
case 'soon':
|
||||
return this.$L('未来 3 天内暂无到期任务')
|
||||
return this.$L('未来 (*) 天内暂无到期任务', 3)
|
||||
case 'hi':
|
||||
return this.$L('暂无高优先级任务')
|
||||
case 'noowner':
|
||||
|
||||
@ -50,7 +50,7 @@
|
||||
<div v-if="canKickMember(item)" class="user-exit" @click.stop="onExit(item)"><Icon type="md-exit"/></div>
|
||||
</li>
|
||||
<li class="label">
|
||||
<span>{{$L(`群成员 (${userList.length}人)`)}}</span>
|
||||
<span>{{$L('群成员 ((*)人)', userList.length)}}</span>
|
||||
</li>
|
||||
</template>
|
||||
<li v-for="item in userList" @click="openUser(item.userid)">
|
||||
|
||||
@ -33,7 +33,7 @@
|
||||
<div class="initiate">
|
||||
<span>{{ $L('由') }}</span>
|
||||
<UserAvatar :userid="createId" :size="22" :showName="true"/>
|
||||
<span> {{ $L('发起,参与接龙目前共'+num+'人') }}</span>
|
||||
<span> {{ $L('发起,参与接龙目前共(*)人', num) }}</span>
|
||||
</div>
|
||||
<div class="textarea">
|
||||
<Input ref="wordChainTextareaRef"
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="dialog-session-history">
|
||||
<div class="session-history-title">{{$L('与 (*) 会话历史', sessionData.name)}}</div>
|
||||
<div class="session-history-title">{{$L('与(*)会话历史', sessionData.name)}}</div>
|
||||
<Scrollbar
|
||||
ref="list"
|
||||
class="session-history-list"
|
||||
|
||||
@ -63,7 +63,7 @@
|
||||
<li v-if="uindex < emojiUsersNum" :key="`emoji-user-li-${uindex}-${uitem}`">
|
||||
<UserAvatar :userid="uitem" show-name :show-icon="false"/>
|
||||
</li>
|
||||
<li v-else-if="uindex == emojiUsersNum" :key="`emoji-user-more-${uindex}`">+{{item.userids.length - emojiUsersNum}}位</li>
|
||||
<li v-else-if="uindex == emojiUsersNum" :key="`emoji-user-more-${uindex}`">{{$L('+(*)位', item.userids.length - emojiUsersNum)}}</li>
|
||||
</template>
|
||||
</ul>
|
||||
</div>
|
||||
@ -75,7 +75,7 @@
|
||||
<!--回复数-->
|
||||
<div v-if="!hideReply && msgData.reply_num > 0" class="reply" @click="replyList">
|
||||
<i class="taskfont"></i>
|
||||
{{msgData.reply_num}}条回复
|
||||
{{$L('(*)条回复', msgData.reply_num)}}
|
||||
</div>
|
||||
<!--标注-->
|
||||
<div v-if="msgData.tag" class="tag" @click="openTag">
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="open-approve-details" :data-id="msg.data.id">
|
||||
<b>{{ $L(`${msg.data.comment_nickname} 评论了 ${msg.data.nickname} 的「${msg.data.proc_def_name}」审批`) }}</b>
|
||||
<b>{{ $L('(*)评论了(*)的「(*)」审批', msg.data.comment_nickname, msg.data.nickname, $L(msg.data.proc_def_name)) }}</b>
|
||||
<div class="cause">
|
||||
<p>{{$L('申请人')}}:<span class="mark-color">@{{ msg.data.nickname }}</span> {{ msg.data.department }}</p>
|
||||
<b>{{$L('评论内容')}}</b>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="open-approve-details" :data-id="msg.data.id">
|
||||
<b>{{ $L(`抄送 ${msg.data.nickname} 提交的「${msg.data.proc_def_name}」记录`) }}</b>
|
||||
<b>{{ $L('抄送(*)提交的「(*)」记录', msg.data.nickname, $L(msg.data.proc_def_name)) }}</b>
|
||||
<div class="cause">
|
||||
<p>{{$L("状态")}}:<b>{{ msg.is_finished ? $L("已完成") : $L("审批中") }}</b></p>
|
||||
<p>{{$L("申请人")}}:<span class="mark-color">@{{ msg.data.nickname }}</span> {{ msg.data.department }}</p>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="open-approve-details" :data-id="msg.data.id">
|
||||
<b>{{ $L(`${msg.data.nickname} 提交的「${msg.data.proc_def_name}」待你审批`) }}</b>
|
||||
<b>{{ $L('(*)提交的「(*)」待你审批', msg.data.nickname, $L(msg.data.proc_def_name)) }}</b>
|
||||
<div class="cause">
|
||||
<p>{{$L("状态")}}:<b>{{ $L(statusText) }}</b></p>
|
||||
<p>{{$L("申请人")}}:<span class="mark-color">@{{ msg.data.nickname }}</span> {{ msg.data.department }}</p>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="open-approve-details" :data-id="msg.data.id">
|
||||
<b>{{ $L(title) }}</b>
|
||||
<b>{{ title }}</b>
|
||||
<div class="cause">
|
||||
<p>{{$L("状态")}}:<b>{{ $L(statusText) }}</b></p>
|
||||
<p>{{$L("申请人")}}:<span class="mark-color">@{{ msg.data.start_nickname }}</span> {{ msg.data.department }}</p>
|
||||
@ -23,7 +23,10 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
title({msg}) {
|
||||
return msg.action === 'pass' ? `您发起的「${msg.data.proc_def_name}」已通过` : `您发起的「${msg.data.proc_def_name}」被 ${msg.data.nickname} 拒绝`
|
||||
const name = this.$L(msg.data.proc_def_name)
|
||||
return msg.action === 'pass'
|
||||
? this.$L('您发起的「(*)」已通过', name)
|
||||
: this.$L('您发起的「(*)」被(*)拒绝', name, msg.data.nickname)
|
||||
},
|
||||
statusText({msg}) {
|
||||
switch (msg.action) {
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
|
||||
<script>
|
||||
import DialogMarkdown from "../../DialogMarkdown.vue";
|
||||
import {languageName} from "../../../../../language";
|
||||
import {languageName} from "../../../../../i18n";
|
||||
|
||||
export default {
|
||||
components: {DialogMarkdown},
|
||||
|
||||
@ -237,7 +237,7 @@
|
||||
<div v-if="!isStaticMode && multiSelectMode" class="dialog-multi-select-bar">
|
||||
<div class="multi-select-info">
|
||||
<span>{{ $L('已选(*)条', selectedMsgIds.length) }}</span>
|
||||
<span v-if="selectedMsgIds.length >= 100" class="multi-select-max">{{ $L('(最多100条)') }}</span>
|
||||
<span v-if="selectedMsgIds.length >= 100" class="multi-select-max">{{ $L('(最多(*)条)', 100) }}</span>
|
||||
</div>
|
||||
<div class="multi-select-actions">
|
||||
<Button type="primary" size="small" :disabled="selectedMsgIds.length === 0" @click="onMultiForward">{{ $L('转发') }}</Button>
|
||||
@ -461,7 +461,7 @@
|
||||
:title="$L('修改资料')"
|
||||
:mask-closable="false">
|
||||
<Form :model="modifyData" v-bind="formOptions" @submit.native.prevent>
|
||||
<Alert v-if="modifyData.system_name" type="error" style="margin-bottom:18px">{{$L(`正在修改系统机器人:${modifyData.system_name}`)}}</Alert>
|
||||
<Alert v-if="modifyData.system_name" type="error" style="margin-bottom:18px">{{$L('正在修改系统机器人:(*)', modifyData.system_name)}}</Alert>
|
||||
<FormItem prop="avatar" :label="$L('头像')">
|
||||
<ImgUpload v-model="modifyData.avatar" :num="1" :width="512" :height="512" whcut="cover"/>
|
||||
</FormItem>
|
||||
@ -743,7 +743,7 @@ import touchclick from "../../../directives/touchclick";
|
||||
import longpress from "../../../directives/longpress";
|
||||
import TransferDom from "../../../directives/transfer-dom";
|
||||
import resizeObserver from "../../../directives/resize-observer";
|
||||
import {languageList} from "../../../language";
|
||||
import {languageList} from "../../../i18n";
|
||||
import {isLocalHost} from "../../../components/Replace/utils";
|
||||
import emitter from "../../../store/events";
|
||||
import Forwarder from "./Forwarder/index.vue";
|
||||
@ -1323,7 +1323,7 @@ export default {
|
||||
if (unread_one && unread_one < startMsgId) {
|
||||
array.push({
|
||||
type: 'unread',
|
||||
label: this.$L(`未读消息${not}条`),
|
||||
label: this.$L('未读消息(*)条', not),
|
||||
msg_id: unread_one
|
||||
})
|
||||
}
|
||||
@ -1331,7 +1331,7 @@ export default {
|
||||
array.push(...mention_ids.map(msg_id => {
|
||||
return {
|
||||
type: 'mention',
|
||||
label: this.$L(`@我的消息`),
|
||||
label: this.$L('@我的消息'),
|
||||
msg_id
|
||||
}
|
||||
}))
|
||||
@ -3165,7 +3165,7 @@ export default {
|
||||
} else if (this.selectedMsgIds.length < 100) {
|
||||
this.selectedMsgIds.push(msgId);
|
||||
} else {
|
||||
$A.messageWarning(this.$L('最多选择100条消息'));
|
||||
$A.messageWarning(this.$L('最多选择(*)条消息', 100));
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@ -217,7 +217,7 @@ export default {
|
||||
const vNode = [
|
||||
h('Poptip', {
|
||||
props: {
|
||||
title: this.$L(`确定要取消收藏"${params.row.name}"吗?`),
|
||||
title: this.$L('确定要取消收藏"(*)"吗?', params.row.name),
|
||||
confirm: true,
|
||||
transfer: true,
|
||||
placement: 'left',
|
||||
|
||||
@ -309,7 +309,7 @@
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex';
|
||||
import { languageName } from "../../../language";
|
||||
import { languageName } from "../../../i18n";
|
||||
|
||||
export default {
|
||||
name: "MCPHelper",
|
||||
|
||||
@ -128,7 +128,7 @@ import DragBallComponent from "../../../../components/DragBallComponent";
|
||||
import UserSelect from "../../../../components/UserSelect.vue";
|
||||
import emitter from "../../../../store/events";
|
||||
import {getErrorMessage} from "./utils";
|
||||
import {languageName} from "../../../../language";
|
||||
import {languageName} from "../../../../i18n";
|
||||
|
||||
export default {
|
||||
name: "MeetingManager",
|
||||
|
||||
@ -338,7 +338,7 @@ export default {
|
||||
list.push({
|
||||
id,
|
||||
button: this.$L('重置'),
|
||||
content: this.$L(`确定重置为【${name}】吗?`),
|
||||
content: this.$L('确定重置为【(*)】吗?', name),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -20,7 +20,7 @@
|
||||
</li>
|
||||
<template v-if="!(windowWidth <= 980 || projectData.cacheParameter.chat) && projectUser.length > 0" v-for="item in projectUser">
|
||||
<li v-if="item.userid === -1" class="more">
|
||||
<ETooltip :disabled="$isEEUIApp || windowTouch" :content="$L('共' + (projectData.project_user.length) + '个成员')">
|
||||
<ETooltip :disabled="$isEEUIApp || windowTouch" :content="$L('共(*)个成员', projectData.project_user.length)">
|
||||
<Icon type="ios-more"/>
|
||||
</ETooltip>
|
||||
</li>
|
||||
@ -426,7 +426,7 @@
|
||||
</RadioGroup>
|
||||
<div v-if="settingData.archive_method==='system'" class="form-tip">{{$L('根据系统设置的自动归档规则执行')}}</div>
|
||||
<template v-else-if="settingData.archive_method=='custom'">
|
||||
<div class="form-tip">{{$L('任务完成 (*) 天后自动归档。', settingData.archive_days || 'n')}}</div>
|
||||
<div class="form-tip">{{$L('任务完成(*)天后自动归档。', settingData.archive_days || 'n')}}</div>
|
||||
<div class="setting-auto-day">
|
||||
<Input v-model="settingData.archive_days" type="number">
|
||||
<span slot="append">{{$L('天')}}</span>
|
||||
|
||||
@ -51,7 +51,7 @@
|
||||
|
||||
<script>
|
||||
import { mapState } from 'vuex'
|
||||
import {languageName} from "../../../../language";
|
||||
import {languageName} from "../../../../i18n";
|
||||
import {systemTags} from "./utils";
|
||||
import Tags from "./tags.vue";
|
||||
|
||||
|
||||
@ -109,7 +109,7 @@ export default {
|
||||
newValue = this.value.filter(item => item.name !== tag.name);
|
||||
} else {
|
||||
if (this.max > 0 && this.value.length >= this.max) {
|
||||
$A.messageWarning(this.$L('最多只能选择 (*) 个标签', this.max));
|
||||
$A.messageWarning(this.$L('最多只能选择(*)个标签', this.max));
|
||||
return;
|
||||
}
|
||||
newValue = [...this.value, { name: tag.name, color: tag.color }];
|
||||
|
||||
@ -136,7 +136,7 @@ import {mapState} from 'vuex'
|
||||
import Draggable from 'vuedraggable';
|
||||
import VMPreviewNostyle from "../../../../components/VMEditor/nostyle.vue";
|
||||
import AllTaskTemplates from "./templates";
|
||||
import {languageName} from "../../../../language";
|
||||
import {languageName} from "../../../../i18n";
|
||||
|
||||
export default {
|
||||
name: 'ProjectTaskTemplate',
|
||||
|
||||
@ -218,14 +218,14 @@
|
||||
<Radio label="replace">{{$L('流转模式')}}</Radio>
|
||||
<Radio label="merge">{{$L('剔除模式')}}</Radio>
|
||||
</RadioGroup>
|
||||
<div v-if="settingData.usertype=='replace'" class="form-tip">{{$L(`流转到【${settingData.name}】时改变任务负责人为状态负责人,原本的任务负责人移至协助人员。`)}}</div>
|
||||
<div v-else-if="settingData.usertype=='merge'" class="form-tip">{{$L(`流转到【${settingData.name}】时改变任务负责人为状态负责人(并保留操作状态的人员),原本的任务负责人移至协助人员。`)}}</div>
|
||||
<div v-else class="form-tip">{{$L(`流转到【${settingData.name}】时添加状态负责人至任务负责人。`)}}</div>
|
||||
<div v-if="settingData.usertype=='replace'" class="form-tip">{{$L('流转到【(*)】时改变任务负责人为状态负责人,原本的任务负责人移至协助人员。', settingData.name)}}</div>
|
||||
<div v-else-if="settingData.usertype=='merge'" class="form-tip">{{$L('流转到【(*)】时改变任务负责人为状态负责人(并保留操作状态的人员),原本的任务负责人移至协助人员。', settingData.name)}}</div>
|
||||
<div v-else class="form-tip">{{$L('流转到【(*)】时添加状态负责人至任务负责人。', settingData.name)}}</div>
|
||||
</FormItem>
|
||||
<FormItem prop="userlimit" :label="$L('限制负责人')">
|
||||
<iSwitch v-model="settingData.userlimit" :true-value="1" :false-value="0"/>
|
||||
<div v-if="settingData.userlimit===1" class="form-tip">{{$L(`流转到【${settingData.name}】时,[任务负责人] 和 [项目管理员] 可以修改状态。`)}}</div>
|
||||
<div v-else class="form-tip">{{$L(`流转到【${settingData.name}】时,[任务负责人] 和 [项目管理员] 可以修改状态。`)}}</div>
|
||||
<div v-if="settingData.userlimit===1" class="form-tip">{{$L('流转到【(*)】时,[任务负责人] 和 [项目管理员] 可以修改状态。', settingData.name)}}</div>
|
||||
<div v-else class="form-tip">{{$L('流转到【(*)】时,[任务负责人] 和 [项目管理员] 可以修改状态。', settingData.name)}}</div>
|
||||
</FormItem>
|
||||
</div>
|
||||
</div>
|
||||
@ -237,7 +237,7 @@
|
||||
<Option v-for="(item, index) in columnList" :value="item.id" :key="index">{{ item.name }}</Option>
|
||||
</Select>
|
||||
<div class="form-tip">
|
||||
{{$L(`流转到【${settingData.name}】时自动将任务移动至关联列表。`)}}
|
||||
{{$L('流转到【(*)】时自动将任务移动至关联列表。', settingData.name)}}
|
||||
<a v-if="settingData.columnid" href="javascript:void(0)" @click="settingData.columnid=0">{{$L('取消关联')}}</a>
|
||||
</div>
|
||||
</FormItem>
|
||||
|
||||
@ -134,7 +134,7 @@ export default {
|
||||
const actions = [
|
||||
h('Poptip', {
|
||||
props: {
|
||||
title: this.$L(`确定要删除记录"${params.row.name || this.$L('未命名')}"吗?`),
|
||||
title: this.$L('确定要删除记录"(*)"吗?', params.row.name || this.$L('未命名')),
|
||||
confirm: true,
|
||||
transfer: true,
|
||||
placement: 'left',
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
:rows="1"
|
||||
:autosize="{ minRows: 1, maxRows: 3 }"
|
||||
:maxlength="255"
|
||||
:placeholder="$L(typeName + '描述,回车创建')"
|
||||
:placeholder="$L('(*)描述,回车创建', $L(typeName))"
|
||||
enterkeyhint="done"
|
||||
@on-focus="onFocus=true"
|
||||
@on-blur="onFocus=false"
|
||||
@ -30,7 +30,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="add-btn" @click="openAdd">
|
||||
<Icon class="add-icon" type="md-add" />{{$L('添加' + typeName)}}
|
||||
<Icon class="add-icon" type="md-add" />{{$L('添加(*)', $L(typeName))}}
|
||||
</div>
|
||||
</Col>
|
||||
<Col span="3"></Col>
|
||||
@ -46,13 +46,13 @@
|
||||
:rows="2"
|
||||
:autosize="{ minRows: 2, maxRows: 3 }"
|
||||
:maxlength="255"
|
||||
:placeholder="$L(typeName + '描述,回车创建')"
|
||||
:placeholder="$L('(*)描述,回车创建', $L(typeName))"
|
||||
enterkeyhint="done"
|
||||
@on-focus="onFocus=true"
|
||||
@on-blur="onFocus=false"
|
||||
@on-keydown="onKeydown"/>
|
||||
<div class="add-placeholder" @click="openAdd">
|
||||
<Icon type="md-add" />{{$L('添加' + typeName)}}
|
||||
<Icon type="md-add" />{{$L('添加(*)', $L(typeName))}}
|
||||
</div>
|
||||
<div class="priority">
|
||||
<ul>
|
||||
|
||||
@ -304,7 +304,7 @@
|
||||
<i class="taskfont"></i>{{$L('附件')}}
|
||||
</div>
|
||||
<ul class="item-content file">
|
||||
<li v-if="taskDetail.file_num > 50" class="tip">{{$L(`共${taskDetail.file_num}个文件,仅显示最新50个`)}}</li>
|
||||
<li v-if="taskDetail.file_num > 50" class="tip">{{$L('共(*)个文件,仅显示最新50个', taskDetail.file_num)}}</li>
|
||||
<li v-for="(file, index) in fileList" :key="index" @click="showFileDropdown(file, $event)">
|
||||
<img v-if="file.id" class="file-ext" :src="file.thumb"/>
|
||||
<Loading v-else class="file-load"/>
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
<Form ref="exportTask" :model="formData" v-bind="formOptions" @submit.native.prevent>
|
||||
<FormItem :label="$L('导出成员')">
|
||||
<UserSelect v-model="formData.userid" :multiple-max="100" avatar-name show-disable :title="$L('请选择成员')"/>
|
||||
<div class="form-tip">{{$L('每次最多选择导出100个成员')}}</div>
|
||||
<div class="form-tip">{{$L('每次最多选择导出(*)个成员', 100)}}</div>
|
||||
</FormItem>
|
||||
<FormItem :label="$L('时间范围')">
|
||||
<DatePicker
|
||||
|
||||
@ -281,7 +281,7 @@
|
||||
v-model="disableShow"
|
||||
:title="$L('操作离职')">
|
||||
<Form :model="disableData" v-bind="formOptions" @submit.native.prevent>
|
||||
<Alert type="error" style="margin-bottom:18px">{{$L(`正在进行帐号【ID:${disableData.userid}, ${disableData.nickname}】离职操作。`)}}</Alert>
|
||||
<Alert type="error" style="margin-bottom:18px">{{$L('正在进行帐号【ID:(*), (*)】离职操作。', disableData.userid, disableData.nickname)}}</Alert>
|
||||
<FormItem :label="$L('离职时间')">
|
||||
<DatePicker
|
||||
ref="disableTime"
|
||||
@ -296,7 +296,7 @@
|
||||
<FormItem :label="$L('交接人')">
|
||||
<UserSelect v-model="disableData.transfer_userid" :disabled-choice="[disableData.userid]" :multiple-max="1" :title="$L('选择交接人')"/>
|
||||
<div class="form-tip">{{ $L('可选,留空则不执行迁移') }}</div>
|
||||
<div class="form-tip">{{ $L(`${disableData.nickname} 负责的部门、项目、任务和文件将移交给交接人;同时退出所有群(如果是群主则转让给交接人)`) }}</div>
|
||||
<div class="form-tip">{{ $L('(*) 负责的部门、项目、任务和文件将移交给交接人;同时退出所有群(如果是群主则转让给交接人)', disableData.nickname) }}</div>
|
||||
</FormItem>
|
||||
</Form>
|
||||
<div slot="footer" class="adaption">
|
||||
@ -1245,7 +1245,7 @@ export default {
|
||||
|
||||
$A.modalConfirm({
|
||||
title: this.$L('同步部门成员'),
|
||||
content: `<div>${this.$L(`你确定要同步部门成员吗?`)}</div><div style="color:#f00;font-weight:600">${this.$L(`注:此操作会同步子部门成员到当前部门`)}</div>`,
|
||||
content: `<div>${this.$L('你确定要同步部门成员吗?')}</div><div style="color:#f00;font-weight:600">${this.$L('注:此操作会同步子部门成员到当前部门')}</div>`,
|
||||
language: false,
|
||||
loading: true,
|
||||
onOk: () => {
|
||||
@ -1272,7 +1272,7 @@ export default {
|
||||
if (delItem) {
|
||||
$A.modalConfirm({
|
||||
title: this.$L('删除部门'),
|
||||
content: `<div>${this.$L(`你确定要删除【${delItem.name}】部门吗?`)}</div><div style="color:#f00;font-weight:600">${this.$L(`注意:此操作不可恢复,部门下的成员将移至默认部门。`)}</div>`,
|
||||
content: `<div>${this.$L('你确定要删除【(*)】部门吗?', delItem.name)}</div><div style="color:#f00;font-weight:600">${this.$L('注意:此操作不可恢复,部门下的成员将移至默认部门。')}</div>`,
|
||||
language: false,
|
||||
loading: true,
|
||||
onOk: () => {
|
||||
|
||||
@ -90,7 +90,7 @@
|
||||
class="manage-tags-btn icon"
|
||||
@click="onOpenTagsModal"
|
||||
>
|
||||
<Icon type="ios-settings-outline" /> 管理
|
||||
<Icon type="ios-settings-outline" /> {{$L('管理')}}
|
||||
</Button>
|
||||
</div>
|
||||
<div v-else class="tags-empty">
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
width="560">
|
||||
<Form :model="formData" v-bind="formOptions" @submit.native.prevent>
|
||||
<Alert type="warning" style="margin-bottom:18px">
|
||||
{{ $L(`正在编辑帐号【ID:${userData.userid}, ${userData.nickname}】的信息。`) }}
|
||||
{{ $L('正在编辑帐号【ID:(*), (*)】的信息。', userData.userid, userData.nickname) }}
|
||||
</Alert>
|
||||
|
||||
<FormItem :label="$L('昵称')">
|
||||
@ -98,7 +98,7 @@
|
||||
<template v-if="checkinMode">
|
||||
<FormItem :label="$L('人脸图片')" class="checkin-field">
|
||||
<ImgUpload v-model="formData.faceimg" :num="1" :width="512" :height="512" whcut="cover"/>
|
||||
<div class="form-tip">{{ $L('建议尺寸:500x500') }}</div>
|
||||
<div class="form-tip">{{ $L('建议尺寸:(*)', '500x500') }}</div>
|
||||
</FormItem>
|
||||
|
||||
<FormItem :label="$L('MAC地址')" class="checkin-field">
|
||||
|
||||
@ -87,13 +87,13 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="tag-meta-info" v-if="tag.created_by_name">
|
||||
<span>{{$L('由 (*) 创建', tag.created_by_name)}}</span>
|
||||
<span>{{$L('由(*)创建', tag.created_by_name)}}</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div v-if="total > 0" class="tag-modal-footer">
|
||||
<span>{{$L('当前共 (*) 个标签', total)}}</span>
|
||||
<span>{{$L('当前共(*)个标签', total)}}</span>
|
||||
</div>
|
||||
</div>
|
||||
</ModalAlive>
|
||||
@ -242,7 +242,7 @@ export default {
|
||||
return;
|
||||
}
|
||||
if (name.length > 20) {
|
||||
$A.messageError(this.$L('标签名称最多只能设置20个字'));
|
||||
$A.messageError(this.$L('标签名称最多只能设置(*)个字', 20));
|
||||
return;
|
||||
}
|
||||
if (this.pending.add) {
|
||||
@ -288,7 +288,7 @@ export default {
|
||||
return;
|
||||
}
|
||||
if (name.length > 20) {
|
||||
$A.messageError(this.$L('标签名称最多只能设置20个字'));
|
||||
$A.messageError(this.$L('标签名称最多只能设置(*)个字', 20));
|
||||
return;
|
||||
}
|
||||
if (name === tag.name) {
|
||||
|
||||
@ -30,7 +30,7 @@
|
||||
trigger="click">
|
||||
<div class="dashboard-cache-popover">
|
||||
<strong>{{$L('数据更新说明')}}</strong>
|
||||
<p>{{$L('页面统计数据在 60 秒内复用,重点关注任务列表除外。')}}</p>
|
||||
<p>{{$L('页面统计数据在 (*) 秒内复用,重点关注任务列表除外。', 60)}}</p>
|
||||
<span>{{$L('上次更新:(*)', teamStatsUpdatedTime)}}</span>
|
||||
<Button
|
||||
type="primary"
|
||||
@ -585,24 +585,20 @@ export default {
|
||||
},
|
||||
|
||||
dashboardHello({systemConfig, userInfo, nowTime}) {
|
||||
let hello;
|
||||
if (systemConfig.system_welcome) {
|
||||
hello = systemConfig.system_welcome;
|
||||
} else {
|
||||
const hour = $A.daytz(nowTime).hour();
|
||||
if (hour < 5) {
|
||||
hello = '夜深了,{username}';
|
||||
} else if (hour < 11) {
|
||||
hello = '早上好,{username}';
|
||||
} else if (hour < 14) {
|
||||
hello = '中午好,{username}';
|
||||
} else if (hour < 18) {
|
||||
hello = '下午好,{username}';
|
||||
} else {
|
||||
hello = '晚上好,{username}';
|
||||
}
|
||||
return this.$L(systemConfig.system_welcome).replace(/\{username}/g, userInfo.nickname);
|
||||
}
|
||||
return this.$L(hello).replace(/\{username}/g, userInfo.nickname);
|
||||
const hour = $A.daytz(nowTime).hour();
|
||||
if (hour < 5) {
|
||||
return this.$L('夜深了,(*)', userInfo.nickname);
|
||||
} else if (hour < 11) {
|
||||
return this.$L('早上好,(*)', userInfo.nickname);
|
||||
} else if (hour < 14) {
|
||||
return this.$L('中午好,(*)', userInfo.nickname);
|
||||
} else if (hour < 18) {
|
||||
return this.$L('下午好,(*)', userInfo.nickname);
|
||||
}
|
||||
return this.$L('晚上好,(*)', userInfo.nickname);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@ -72,7 +72,7 @@
|
||||
<div class="file-shear">
|
||||
<span>{{$L('粘贴')}}</span>
|
||||
<template v-show="showBtnText">"<em>{{shearFirst.name}}</em>"</template>
|
||||
<span v-if="shearIds.length > 1">{{ $L(`等${shearIds.length}个文件`) }}</span>
|
||||
<span v-if="shearIds.length > 1">{{ $L('等(*)个文件', shearIds.length) }}</span>
|
||||
</div>
|
||||
</Button>
|
||||
<Button type="primary" size="small" @click="clearShear">{{ $L('取消剪切') }}</Button>
|
||||
@ -2000,7 +2000,7 @@ export default {
|
||||
$A.messageWarning("请等待打包完成");
|
||||
return;
|
||||
}
|
||||
const name = this.$L(`打包下载${fileName}`)
|
||||
const name = this.$L('打包下载(*)', fileName)
|
||||
this.$store.dispatch("call", {
|
||||
url: 'file/download/pack',
|
||||
data: {ids, name},
|
||||
|
||||
@ -155,8 +155,8 @@
|
||||
</ul>
|
||||
</li>
|
||||
<li class="loaded">
|
||||
<template v-if="contactsKey">{{$L('搜索到' + contactsFilter.length + '位联系人')}}</template>
|
||||
<template v-else>{{$L('共' + contactsTotal + '位联系人')}}</template>
|
||||
<template v-if="contactsKey">{{$L('搜索到(*)位联系人', contactsFilter.length)}}</template>
|
||||
<template v-else>{{$L('共(*)位联系人', contactsTotal)}}</template>
|
||||
</li>
|
||||
</template>
|
||||
<li v-else-if="contactsLoad == 0" class="nothing">
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
<Row class="setting-template">
|
||||
<Col span="24">
|
||||
<ImgUpload v-model="faceimgs" :num="1" :width="512" :height="512" whcut="cover"/>
|
||||
<div class="form-tip">{{ $L('建议尺寸:500x500') }}</div>
|
||||
<div class="form-tip">{{ $L('建议尺寸:(*)', '500x500') }}</div>
|
||||
</Col>
|
||||
</Row>
|
||||
</TabPane>
|
||||
|
||||
@ -146,7 +146,7 @@
|
||||
<template v-if="formData.locat_bd_lbs_point.lng">
|
||||
<div class="form-tip">
|
||||
<a href="javascript:void(0)" @click="openMapSelect">
|
||||
{{ $L(`经度:${formData.locat_bd_lbs_point.lng},纬度:${formData.locat_bd_lbs_point.lat},半径:${formData.locat_bd_lbs_point.radius}米`) }}
|
||||
{{ $L('经度:(*),纬度:(*),半径:(*)米', formData.locat_bd_lbs_point.lng, formData.locat_bd_lbs_point.lat, formData.locat_bd_lbs_point.radius) }}
|
||||
</a>
|
||||
</div>
|
||||
<div class="form-tip" @click="openMapSelect">{{$L('点击修改允许签到位置')}}</div>
|
||||
@ -165,7 +165,7 @@
|
||||
<template v-if="formData.locat_amap_point.lng">
|
||||
<div class="form-tip">
|
||||
<a href="javascript:void(0)" @click="openMapSelect">
|
||||
{{ $L(`经度:${formData.locat_amap_point.lng},纬度:${formData.locat_amap_point.lat},半径:${formData.locat_amap_point.radius}米`) }}
|
||||
{{ $L('经度:(*),纬度:(*),半径:(*)米', formData.locat_amap_point.lng, formData.locat_amap_point.lat, formData.locat_amap_point.radius) }}
|
||||
</a>
|
||||
</div>
|
||||
<div class="form-tip" @click="openMapSelect">{{$L('点击修改允许签到位置')}}</div>
|
||||
@ -184,7 +184,7 @@
|
||||
<template v-if="formData.locat_tencent_point.lng">
|
||||
<div class="form-tip">
|
||||
<a href="javascript:void(0)" @click="openMapSelect">
|
||||
{{ $L(`经度:${formData.locat_tencent_point.lng},纬度:${formData.locat_tencent_point.lat},半径:${formData.locat_tencent_point.radius}米`) }}
|
||||
{{ $L('经度:(*),纬度:(*),半径:(*)米', formData.locat_tencent_point.lng, formData.locat_tencent_point.lat, formData.locat_tencent_point.radius) }}
|
||||
</a>
|
||||
</div>
|
||||
<div class="form-tip" @click="openMapSelect">{{$L('点击修改允许签到位置')}}</div>
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
v-bind="formOptions"
|
||||
@submit.native.prevent>
|
||||
<div class="block-setting-box">
|
||||
<h3>AgoraIO 声网</h3>
|
||||
<h3>{{$L('AgoraIO 声网')}}</h3>
|
||||
<div class="form-box">
|
||||
<FormItem :label="$L('会议功能')" prop="open">
|
||||
<RadioGroup v-model="formData.open">
|
||||
|
||||
@ -119,7 +119,7 @@
|
||||
<span slot="append">{{$L('天')}}</span>
|
||||
</Input>
|
||||
</div>
|
||||
<div slot="content">{{$L('任务完成 (*) 天后自动归档。', formDatum.archived_day || 'n')}}</div>
|
||||
<div slot="content">{{$L('任务完成(*)天后自动归档。', formDatum.archived_day || 'n')}}</div>
|
||||
</ETooltip>
|
||||
</FormItem>
|
||||
<FormItem :label="$L('可见性选项')" prop="taskVisible">
|
||||
@ -292,9 +292,9 @@
|
||||
</FormItem>
|
||||
<FormItem :label="$L('欢迎词')" prop="system_welcome">
|
||||
<div style="width: 220px;">
|
||||
<Input v-model="formDatum.system_welcome" :placeholder="$L('欢迎您,{username}')"/>
|
||||
<Input v-model="formDatum.system_welcome" :placeholder="$L('欢迎您,(*)', '{username}')"/>
|
||||
</div>
|
||||
<div class="form-tip">{{$L('仪表盘欢迎词,{username} 代表用户昵称')}}</div>
|
||||
<div class="form-tip">{{$L('仪表盘欢迎词,(*)代表用户昵称', '{username}')}}</div>
|
||||
</FormItem>
|
||||
<FormItem :label="$L('图片优化')" prop="image_compress">
|
||||
<RadioGroup v-model="formDatum.image_compress">
|
||||
|
||||
@ -25,7 +25,7 @@
|
||||
</div>
|
||||
<Modal
|
||||
v-model="warningShow"
|
||||
:title="$L(`删除${appTitle}帐号`)"
|
||||
:title="$L('删除(*)帐号', appTitle)"
|
||||
class="page-setting-delete-box">
|
||||
<div class="big-text">{{ $L('帐号删除后,该帐号将无法正常登录且无法恢复,帐号下的所有数据也将被删除。') }}</div>
|
||||
<div class="small-text">
|
||||
@ -63,9 +63,9 @@ export default {
|
||||
{
|
||||
validator: (rule, value, callback) => {
|
||||
if (value.trim() === '') {
|
||||
callback(new Error(this.$L('请输入邮箱帐号!')));
|
||||
callback(new Error(this.$L('请输入邮箱帐号')));
|
||||
} else if (!$A.isEmail(value.trim())) {
|
||||
callback(new Error(this.$L('请输入正确邮箱帐号!')));
|
||||
callback(new Error(this.$L('请输入正确的邮箱地址!')));
|
||||
} else {
|
||||
callback();
|
||||
}
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
<div class="setting-item submit">
|
||||
<Loading v-if="configLoad > 0"/>
|
||||
<Form v-else ref="formDatum" :model="formDatum" :rules="ruleDatum" v-bind="formOptions" @submit.native.prevent>
|
||||
<Alert v-if="isLdap" type="warning">{{$L('LDAP 用户禁止修改邮箱地址')}}</Alert>
|
||||
<Alert v-if="isLdap" type="warning">{{$L('LDAP 用户禁止修改邮箱')}}</Alert>
|
||||
<FormItem :label="$L('新邮箱地址')" prop="newEmail">
|
||||
<Input v-if="isRegVerify == 1" v-model="formDatum.newEmail"
|
||||
:class="count > 0 ? 'setting-send-input':'setting-input'" search @on-search="sendEmailCode"
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {languageList, languageName, setLanguage} from "../../../language";
|
||||
import {languageList, languageName, setLanguage} from "../../../i18n";
|
||||
import {mapState} from "vuex";
|
||||
|
||||
export default {
|
||||
|
||||
@ -36,7 +36,7 @@ export default {
|
||||
ruleDatum: {
|
||||
oldpass: [
|
||||
{ required: true, message: this.$L('请输入旧密码!'), trigger: 'change' },
|
||||
{ type: 'string', min: 6, message: this.$L('密码长度至少6位!'), trigger: 'change' }
|
||||
{ type: 'string', min: 6, message: this.$L('密码长度至少(*)位!', 6), trigger: 'change' }
|
||||
],
|
||||
newpass: [
|
||||
{
|
||||
@ -53,7 +53,7 @@ export default {
|
||||
required: true,
|
||||
trigger: 'change'
|
||||
},
|
||||
{ type: 'string', min: 6, message: this.$L('密码长度至少6位!'), trigger: 'change' }
|
||||
{ type: 'string', min: 6, message: this.$L('密码长度至少(*)位!', 6), trigger: 'change' }
|
||||
],
|
||||
checkpass: [
|
||||
{
|
||||
|
||||
@ -8,7 +8,7 @@
|
||||
@submit.native.prevent>
|
||||
<FormItem :label="$L('头像')" prop="userimg">
|
||||
<ImgUpload v-model="formData.userimg" :num="1" :width="512" :height="512" whcut="cover"/>
|
||||
<span class="form-tip">{{$L('建议尺寸:200x200')}}</span>
|
||||
<span class="form-tip">{{$L('建议尺寸:(*)', '200x200')}}</span>
|
||||
</FormItem>
|
||||
<FormItem :label="$L('邮箱')" prop="email">
|
||||
<Input v-model="userInfo.email" disabled></Input>
|
||||
@ -113,7 +113,7 @@ export default {
|
||||
],
|
||||
nickname: [
|
||||
{required: true, message: this.$L('请输入昵称!'), trigger: 'change'},
|
||||
{type: 'string', min: 2, message: this.$L('昵称长度至少2位!'), trigger: 'change'}
|
||||
{type: 'string', min: 2, message: this.$L('昵称长度至少(*)位!', 2), trigger: 'change'}
|
||||
]
|
||||
},
|
||||
|
||||
|
||||
@ -2,7 +2,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import {languageName} from "../language";
|
||||
import {languageName} from "../i18n";
|
||||
|
||||
export default {
|
||||
mounted() {
|
||||
|
||||
6
resources/assets/js/store/actions.js
vendored
6
resources/assets/js/store/actions.js
vendored
@ -1,5 +1,5 @@
|
||||
import * as openpgp from 'openpgp_hi/lightweight';
|
||||
import {initLanguage, languageList, languageName} from "../language";
|
||||
import {initLanguage, languageList, languageName} from "../i18n";
|
||||
import {$callData, $urlSafe, SSEClient} from '../utils'
|
||||
import {isLocalHost} from "../components/Replace/utils";
|
||||
import emitter from "./events";
|
||||
@ -344,7 +344,7 @@ export default {
|
||||
dispatch("userEditInput", 'nickname').then(() => {
|
||||
dispatch("call", cloneParams).then(resolve).catch(reject)
|
||||
}).catch(err => {
|
||||
reject({ret: -1, data, msg: err || $A.L('请设置昵称!')})
|
||||
reject({ret: -1, data, msg: err || $A.L('请设置昵称')})
|
||||
})
|
||||
return
|
||||
}
|
||||
@ -354,7 +354,7 @@ export default {
|
||||
dispatch("userEditInput", 'tel').then(() => {
|
||||
dispatch("call", cloneParams).then(resolve).catch(reject)
|
||||
}).catch(err => {
|
||||
reject({ret: -1, data, msg: err || $A.L('请设置联系电话!')})
|
||||
reject({ret: -1, data, msg: err || $A.L('请设置联系电话')})
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
2
resources/assets/js/store/chunkedUpload.js
vendored
2
resources/assets/js/store/chunkedUpload.js
vendored
@ -4,7 +4,7 @@
|
||||
import axios from 'axios'
|
||||
import SparkMD5 from 'spark-md5'
|
||||
import store from './index'
|
||||
import { languageName } from '../language'
|
||||
import { languageName } from '../i18n'
|
||||
|
||||
export const CHUNK_THRESHOLD = 10 * 1024 * 1024
|
||||
export const CHUNK_SIZE = 5 * 1024 * 1024 // 必须与后端 ChunkUpload::CHUNK_SIZE 一致
|
||||
|
||||
2
resources/assets/js/utils/ai.js
vendored
2
resources/assets/js/utils/ai.js
vendored
@ -1,4 +1,4 @@
|
||||
import {languageList, languageName} from "../language";
|
||||
import {languageList, languageName} from "../i18n";
|
||||
|
||||
/**
|
||||
* AI 服务商标识与显示名映射
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
2
types/dootask-globals.d.ts
vendored
2
types/dootask-globals.d.ts
vendored
@ -6,7 +6,7 @@
|
||||
* - resources/assets/js/functions/common.js (基础函数 / localForage / Storage / ihttp / ajaxc / time / sort)
|
||||
* - resources/assets/js/functions/web.js (页面专用 / iviewui 弹窗提示 / dark 暗黑模式)
|
||||
* - resources/assets/js/functions/eeui.js (EEUI App 专用)
|
||||
* $L 来源:resources/assets/js/language/index.js 的 switchLanguage,
|
||||
* $L 来源:resources/assets/js/i18n/index.js 的 switchLanguage,
|
||||
* 挂载于 window.$L、Vue.prototype.$L 以及 $A.L(见 resources/assets/js/app.js)。
|
||||
*
|
||||
* 维护提示:在上述源文件中新增/修改 $.extend 挂载的 $A 方法时,须同步更新本声明文件。
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user