Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(web): react-typed-i18n页面国际化 #833

Merged
merged 75 commits into from
Sep 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
5a83846
仪表盘,用户空间未完成作业,蚂蚁组件,路由的部分国际化
piccaSun Aug 30, 2023
d26cd0a
Merge branch 'master' into use-react-typed-i18n
piccaSun Aug 31, 2023
9489c19
修改添加getAvailableRoutes的翻译函数依赖项
piccaSun Aug 31, 2023
a2a1a62
移动翻译函数至i18n/index.ts
piccaSun Sep 10, 2023
4926986
Merge branch 'master' into use-react-typed-i18n
piccaSun Sep 10, 2023
eb77910
从Cookies或header中获取语言id
piccaSun Sep 11, 2023
725de54
门户系统i18n基本框架
piccaSun Sep 11, 2023
987f487
自定义配置文件中的国际化文本示例
piccaSun Sep 11, 2023
4dac0f9
修改cookie合法判断
piccaSun Sep 12, 2023
40b8e85
中文替换i18n的函数
OYX-1 Sep 12, 2023
c79e6d3
配置文件文本i18n refactor
piccaSun Sep 12, 2023
570be8c
修复镜像构建error
piccaSun Sep 12, 2023
2325f7d
patch react-typed-i18n to ignore exports
ddadaal Sep 12, 2023
7798927
修复门户系统没有客户端上下文时的语言id获取
piccaSun Sep 13, 2023
6dfc12c
修改获取配置文件i18n文本使用类型系统
piccaSun Sep 13, 2023
4c3d241
国际化替换中文
OYX-1 Sep 13, 2023
94048bb
翻译文本提出common
OYX-1 Sep 14, 2023
d340c48
修改schema下获取语言id,替换部分门户系统中文
piccaSun Sep 13, 2023
f0c4a58
增加特殊对象的i18n文字获取函数
piccaSun Sep 14, 2023
1bc0a82
国际化中文替换和user、account的index页路由修复
OYX-1 Sep 14, 2023
2af3868
cluster, app等配置文件国际化处理
ZihanChen821 Sep 14, 2023
320b6ba
feat: mis-web pages 国际化
Miracle575 Sep 14, 2023
e5e9634
解决冲突
tongchong Sep 14, 2023
a1254f8
登录页面i18n
piccaSun Sep 14, 2023
700392d
门户作业,文件管理PageComp文本提取替换
piccaSun Sep 15, 2023
c9d76dd
fix: 对其 en zh_cn 文件
Miracle575 Sep 15, 2023
5c1835d
修改文本key值错误拼写
piccaSun Sep 15, 2023
0641aa4
@lib-server增加getI18nConfigCurrentText
ZihanChen821 Sep 15, 2023
655b79e
Merge branch 'master' into use-react-typed-i18n
piccaSun Sep 15, 2023
88e0ecc
删除auth下i18n.ts
piccaSun Sep 15, 2023
a9bdb69
fix github build
piccaSun Sep 15, 2023
e8d4b17
fix dockerfile
piccaSun Sep 15, 2023
0d0682f
fix dockerfile
piccaSun Sep 15, 2023
9e0af7a
fix scow/doc dockerfile
piccaSun Sep 15, 2023
b62a65d
fix
piccaSun Sep 15, 2023
e955922
add copy patch before fetch
piccaSun Sep 15, 2023
35f1b85
lib/web comp i18n
piccaSun Sep 15, 2023
b395757
管理系统英文文本,除漏页操作日志
piccaSun Sep 15, 2023
124fefc
门户系统英文文本除交互式应用等漏页
piccaSun Sep 15, 2023
88aeaff
补充账户消费记录导航
piccaSun Sep 15, 2023
bfcf533
管理系统操作日志显示国际化
piccaSun Sep 16, 2023
6f04f10
补充门户剩余文本提取
piccaSun Sep 16, 2023
eeacdd5
fix title ReactNode
piccaSun Sep 16, 2023
9e77da2
修复与选择集群相关的页面跳转bug
piccaSun Sep 16, 2023
2fd2758
整理auth和libWeb文本到cn和en
piccaSun Sep 17, 2023
9e8f845
补充管理系统及门户系统遗漏文本
piccaSun Sep 17, 2023
e2ade55
直接返回翻译函数
piccaSun Sep 17, 2023
6a88a64
bug fix
piccaSun Sep 17, 2023
067a60a
更改账户正常英文显示Available,补充管理系统个人信息漏项
piccaSun Sep 18, 2023
773b4ca
主题模式切换bug修复
piccaSun Sep 18, 2023
51697c1
集群选择时已选中label不随着语言而改变bug修复
piccaSun Sep 18, 2023
c00ebcf
管理系统下用户可见分区集群显示及下方集群说明国际化的bug修复
piccaSun Sep 18, 2023
2162a2c
去掉多余的引入,补充当前配置文件中可国际化文本并注释掉
piccaSun Sep 18, 2023
acbe2af
修改使用getI18nText通用函数
piccaSun Sep 18, 2023
3dfa538
增加登录页面英文文本漏项bindOtp
piccaSun Sep 19, 2023
19377aa
登录页面placeholder显示修正,otp登录页面系统文本补充
piccaSun Sep 19, 2023
6b61a49
补充系统初始化页面用户角色漏项,英语文本添加空格
piccaSun Sep 19, 2023
808185e
门户选择单个集群bug修复
piccaSun Sep 20, 2023
82b0538
合并merge,修改操作日志国际化
piccaSun Sep 20, 2023
3d0f218
门户集群Selector添加labelInValue
piccaSun Sep 20, 2023
0661c33
修改门户集群查找name时的错误,恢复配置文件配置
piccaSun Sep 20, 2023
de93fc4
补充操作日志表单项目名漏项,补充系统初始化文本空格
piccaSun Sep 20, 2023
3472f3a
配置文件国际化允许不配中文英文使用默认值
piccaSun Sep 20, 2023
416d8ec
修复桌面下选择登陆节点后切换语言已选值清空的bug
piccaSun Sep 20, 2023
c60eb06
merge master, 增加等待提示语文本
piccaSun Sep 20, 2023
a7ce159
fix 配置文件读取默认语言时return错误
piccaSun Sep 20, 2023
3639155
fix 登录节点
piccaSun Sep 20, 2023
b0085b2
修改桌面语言切换时重新查询的问题
piccaSun Sep 21, 2023
15c90e6
修改web后端出现的中文文本到前端,并实现国际化
piccaSun Sep 22, 2023
4ce4081
修改交互式应用自定义配置表单文本配置项国际化实现
piccaSun Sep 25, 2023
bda8670
增加自定义配置文档
piccaSun Sep 25, 2023
a48cda1
合并master中的按登录节点地址确定节点
piccaSun Sep 25, 2023
8951ef2
修改changeset
piccaSun Sep 25, 2023
a4965f8
修改变量名,恢复配置文件,修改changeset
piccaSun Sep 25, 2023
f4205e9
锁定react-typed-i18n依赖版本,增加cli/assets/config配置项支持国际化注释
piccaSun Sep 25, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/hungry-candles-fold.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@scow/config": patch
---

使配置文件中文本配置项兼容国际化类型,实现自定义配置文本的国际化展示
12 changes: 12 additions & 0 deletions .changeset/nice-kings-begin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
"@scow/portal-server": patch
"@scow/portal-web": minor
"@scow/mis-web": minor
"@scow/lib-server": patch
"@scow/auth": minor
"@scow/lib-web": minor
"@scow/docs": patch
"@scow/test-adapter": patch
---

实现 SCOW 门户系统与管理系统的页面国际化功能
5 changes: 5 additions & 0 deletions .changeset/proud-garlics-repair.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@scow/grpc-api": patch
---

修改交互式应用的 html 配置表单的 lable 与 placeholder 的 grpc 类型为 i18nStringType
4 changes: 3 additions & 1 deletion apps/auth/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
"liquidjs": "10.8.4",
"@scow/config": "workspace:*",
"@scow/lib-config": "workspace:*",
"@scow/lib-server": "workspace:*",
"@scow/lib-ssh": "workspace:*",
"@scow/utils": "workspace:*",
"@sinclair/typebox": "0.31.1",
Expand All @@ -43,7 +44,8 @@
"pino": "8.15.0",
"nodemailer": "6.9.4",
"qrcode": "1.5.3",
"speakeasy": "2.0.0"
"speakeasy": "2.0.0",
"react-typed-i18n": "2.3.0"
},
"devDependencies": {
"@types/asn1": "0.2.1",
Expand Down
7 changes: 7 additions & 0 deletions apps/auth/src/auth/bindOtpHtml.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@
*/

import { DEFAULT_PRIMARY_COLOR } from "@scow/config/build/ui";
import { getLanguageCookie } from "@scow/lib-server";
import { FastifyReply, FastifyRequest } from "fastify";
import { join } from "path";
import { config, FAVICON_URL } from "src/config/env";
import { uiConfig } from "src/config/ui";
import { AuthTextsType, languages } from "src/i18n";


function parseHostname(req: FastifyRequest): string | undefined {
Expand Down Expand Up @@ -48,7 +50,12 @@

const hostname = parseHostname(req);

// 获取当前语言ID及对应的绑定OTP页面文本
const languageId = getLanguageCookie(req.raw);
const authTexts: AuthTextsType = languages[languageId];

Check warning on line 55 in apps/auth/src/auth/bindOtpHtml.ts

View check run for this annotation

Codecov / codecov/patch

apps/auth/src/auth/bindOtpHtml.ts#L54-L55

Added lines #L54 - L55 were not covered by tests

return rep.status(err ? 401 : 200).view("/otp/bindOtp.liquid", {
authTexts: authTexts,
cssUrl: join(config.BASE_PATH, config.AUTH_BASE_PATH, "/public/assets/tailwind.min.css"),
faviconUrl: join(config.BASE_PATH, FAVICON_URL),
backgroundColor: uiConfig.primaryColor?.defaultColor ?? DEFAULT_PRIMARY_COLOR,
Expand Down
17 changes: 15 additions & 2 deletions apps/auth/src/auth/loginHtml.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@
*/

import { DEFAULT_PRIMARY_COLOR } from "@scow/config/build/ui";
import { getI18nConfigCurrentText, getLanguageCookie } from "@scow/lib-server/build/i18n";
import { FastifyReply, FastifyRequest } from "fastify";
import { join } from "path";
import { createCaptcha } from "src/auth/captcha";
import { authConfig, OtpStatusOptions, ScowLogoType } from "src/config/auth";
import { config, FAVICON_URL, LOGO_URL } from "src/config/env";
import { uiConfig } from "src/config/ui";
import { AuthTextsType, languages } from "src/i18n";


export async function serveLoginHtml(
Expand All @@ -36,8 +38,19 @@ export async function serveLoginHtml(
? await createCaptcha(req.server)
: undefined;

// 获取当前语言ID及对应的登录页面文本
const languageId = getLanguageCookie(req.raw);
const authTexts: AuthTextsType = languages[languageId];

// 获取sloganI18nText
const sloganTitle = getI18nConfigCurrentText(authConfig.ui?.slogan.title, languageId);
const sloganTextArr = authConfig.ui?.slogan.texts.map((text) => {
return getI18nConfigCurrentText(text, languageId);
});

return rep.status(
verifyCaptchaFail ? 400 : err ? 401 : 200).view("login.liquid", {
authTexts: authTexts,
cssUrl: join(config.BASE_PATH, config.AUTH_BASE_PATH, "/public/assets/tailwind.min.css"),
eyeImagePath: join(config.BASE_PATH, config.AUTH_BASE_PATH, "/public/assets/icons/eye.png"),
eyeCloseImagePath: join(config.BASE_PATH, config.AUTH_BASE_PATH, "/public/assets/icons/eye-close.png"),
Expand All @@ -51,8 +64,8 @@ export async function serveLoginHtml(
logoLink: authConfig.ui?.logo.customLogoLink ?? "",
callbackUrl,
sloganColor: authConfig.ui?.slogan.color || "white",
sloganTitle: authConfig.ui?.slogan.title || "",
sloganTextArr: authConfig.ui?.slogan.texts || [],
sloganTitle: sloganTitle || "",
sloganTextArr: sloganTextArr || [],
footerTextColor: authConfig.ui?.footerTextColor || "white",
themeColor: uiConfig.primaryColor?.defaultColor ?? DEFAULT_PRIMARY_COLOR,
err,
Expand Down
18 changes: 16 additions & 2 deletions apps/auth/src/config/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,20 @@ export enum ScowLogoType {
"light" = "light",
}

// 创建配置文件中显示文字项的配置类型
export const createI18nStringSchema = (description: string, defaultValue?: string) => {
return Type.Union([
Type.String(),
Type.Object({
i18n: Type.Object({
default: Type.String({ description: "国际化类型默认值" }),
en: Type.Optional(Type.String({ description: "国际化类型英文值" })),
zh_cn: Type.Optional(Type.String({ description: "国际化类型简体中文值" })),
}),
}),
], { description, default: defaultValue });
};

export const LdapConfigSchema = Type.Object({
url: Type.String({ description: "LDAP地址" }),
searchBase: Type.String({ description: "从哪个节点搜索登录用户对应的LDAP节点" }),
Expand Down Expand Up @@ -166,8 +180,8 @@ export const UiConfigSchema = Type.Object({
}, { default: {} }),
slogan: Type.Object({
color: Type.String({ description: "默认标语文字颜色", default: "white" }),
title: Type.String({ description: "默认标语标题", default: "" }),
texts: Type.Array(Type.String(), { description: "默认 slogan 正文数组", default: []}),
title: createI18nStringSchema("默认标语标题", ""),
texts: Type.Array(createI18nStringSchema(""), { description: "默认 slogan 正文数组", default: []}),
}, { default: {} }),
footerTextColor: Type.String({ description: "默认 footer 文字颜色", default: "white" }),
});
Expand Down
46 changes: 46 additions & 0 deletions apps/auth/src/i18n/en.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* Copyright (c) 2022 Peking University and Peking University Institute for Computing and Digital Economy
* SCOW is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/

export default {
login: {
login: "Log In",
accountPasswordLogin: "Account Password Login",
username: "Username",
password: "Password",
otpVCode: "OTP Verification Code",
inputVCode: "Please enter the verification code",
refreshError: "Refresh failed, please click to retry.",
invalidVCode: "Invalid verification code, please re-enter.",
invalidInput: "Invalid username / password, please check.",
invalidOtp: "Invalid OTP Verification Code, please re-enter.",
bindOtp: "Bind OTP",
},
bindOtp: {
bindOtp: "Bind OTP",
returnLogin: "Return to Login",
userName: "Username",
password: "Password",
invalidUserNamePassword: "Invalid username/password. Please check.",
confirm: "Confirm",
expiredUserInfo: "User information has expired, please bind again!",
bindLimit1: "Please complete binding within ",
bindLimit2: " minutes",
email: "Your Email ",
getBindLink: "Get Binding Link",
bindLinkSended: "Binding link has been sent. Please verify within your email.",
bindLinkFailed1: "Failed to send the binding link. Please try again in ",
bindLinkFailed2: " seconds.",
bindRequestError1: "Do not request binding link frequently. Please try again in ",
bindRequestError2: " seconds.",
reRequestLink: "You can now request the link again.",
},
};
25 changes: 25 additions & 0 deletions apps/auth/src/i18n/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* Copyright (c) 2022 Peking University and Peking University Institute for Computing and Digital Economy
* SCOW is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/

import { languageDictionary } from "react-typed-i18n";


const zh_cn = () => import("./zh_cn").then((x) => x.default);
const en = () => import("./en").then((x) => x.default);

// return language type
export type AuthTextsType = Awaited<ReturnType<typeof zh_cn>>;

export const languages = languageDictionary({
zh_cn,
en,
});
46 changes: 46 additions & 0 deletions apps/auth/src/i18n/zh_cn.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* Copyright (c) 2022 Peking University and Peking University Institute for Computing and Digital Economy
* SCOW is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
* http://license.coscl.org.cn/MulanPSL2
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/

export default {
login: {
login: "登录",
accountPasswordLogin: "账号密码登录",
username: "用户名",
password: "密码",
otpVCode: "OTP验证码",
inputVCode: "请输入验证码",
refreshError: "刷新失败,请点击重试",
invalidVCode: "验证码无效,请重新输入。",
invalidInput: "用户名/密码无效,请检查。",
invalidOtp: "OTP验证码无效,请重新输入。",
bindOtp: "绑定otp",
},
bindOtp: {
bindOtp: "绑定OTP",
returnLogin: "返回登录",
userName: "用户名",
password: "密码",
invalidUserNamePassword: "用户名/密码无效,请检查。",
confirm: "确认",
expiredUserInfo: "用户信息过期,请重新绑定!",
bindLimit1: "请于",
bindLimit2: "分钟内完成绑定",
email: "您的邮箱",
getBindLink: "获取绑定链接",
bindLinkSended: "绑定链接已发送,请在邮箱内进行验证",
bindLinkFailed1: "绑定链接发送失败,请在",
bindLinkFailed2: "秒后重新获取",
bindRequestError1: "请勿频繁获取绑定链接,请在",
bindRequestError2: "秒后重新获取",
reRequestLink: "现在您可以重新获取链接",
},
};
26 changes: 13 additions & 13 deletions apps/auth/views/login.liquid
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<html>

<head>
<title>登录</title>
<title>{{ authTexts.login.login }}</title>
<link href="{{ cssUrl }}" rel="stylesheet">
<link rel="icon" type="image/x-icon" href="{{ faviconUrl }}"></link>
<meta name="viewport" content="width=device-width, initial-scale=1">
Expand Down Expand Up @@ -42,31 +42,31 @@
<div class="w-1/2 h-screen ml-20 flex items-center justify-center">
<div class="w-80 max-w-md min-w-max bg-white rounded-lg py-12">
<form method="post" action="">
<div class="mb-16 text-2xl font-semibold text-center">账号密码登录</div>
<div class="mb-16 text-2xl font-semibold text-center">{{ authTexts.login.accountPasswordLogin }}</div>
<div class="px-14 flex flex-col items-center">
<div class="w-72 mb-10">
<input type='text' name="username" placeholder="用户名" required
<input type='text' name="username" placeholder="{{ authTexts.login.username }}" required
class="px-8 w-full border rounded px-3 py-2 text-gray-700 focus:outline-none" />
</div>
<div class="w-72 mb-10">
<div class="relative flex items-center">
<input id="password" name="password" placeholder="密码" type="password" required
<input id="password" name="password" placeholder="{{ authTexts.login.password }}" type="password" required
class="px-8 w-full border rounded px-3 py-2 text-gray-700 focus:outline-none" />
<div id="eye-elem" class="absolute w-5 h-5 right-3 bg-contain"></div>
</div>
</div>
{% if enableTotp %}
<div class="w-full mb-10">
<div class="flex items-center">
<input name="otpCode" placeholder="OTP验证码" type="text" required
<input name="otpCode" placeholder="{{ authTexts.login.otpVCode }}" type="text" required
class="px-8 w-full py-2 border rounded text-gray-700 focus:outline-none"/>
</div>
</div>
{% endif %}
{% if enableCaptcha %}
<div class="w-full mb-10">
<div class="flex items-center">
<input name="code" placeholder="请输入验证码" type="text" required
<input name="code" placeholder="{{ authTexts.login.inputVCode }}" type="text" required
class=" px-8 w-full border rounded px-3 py-2 text-gray-700 focus:outline-none" />
<div id="captcha" onclick="refreshCaptcha()" class="cursor-pointer">{{ code }}</div>
<script>
Expand All @@ -81,15 +81,15 @@
).then( async function (response) {
captchaDiv.innerHTML = await response.text();
}).catch(() => {
captchaDiv.textContent = "刷新失败,请点击重试"
captchaDiv.textContent = "{{ authTexts.login.refreshError }}"
});
}
</script>
</script>
</div>
</div>

{% if verifyCaptchaFail %}
<p class="my-4 text-center text-red-600">验证码无效,请重新输入。</p>
<p class="my-4 text-center text-red-600">{{ authTexts.login.invalidVCode }}</p>
{% endif %}

{% else %}
Expand All @@ -100,21 +100,21 @@
<input type="hidden" name="callbackUrl" value="{{ callbackUrl }}" />

{% if err %}
<p class="my-4 text-center text-red-600">用户名/密码无效,请检查。</p>
<p class="my-4 text-center text-red-600">{{ authTexts.login.invalidInput }}</p>
{% endif %}
{% if verifyOtpFail %}
<p class="my-4 text-center text-red-600">OTP验证码无效,请重新输入。</p>
<p class="my-4 text-center text-red-600">{{ authTexts.login.invalidOtp }}</p>
{% endif %}
<button type="submit" class="w-72 py-2 mb-14 rounded button-primary text-gray-100 focus:outline-none">
登录
{{ authTexts.login.login }}
</button>
</div>
</form>
{% if showBindOtpButton %}
<div class="px-12 mt-4">
<form action="{{ otpBasePath }}/bind" method="get">
<button type="submit" name="action" value="bindOtp" class="px text-gray-400">
绑定otp
{{ authTexts.login.bindOtp }}
</button>
<input type="hidden" name="callbackUrl" value="{{ callbackUrl }}" />
</form>
Expand Down
Loading
Loading