diff --git a/.github/workflows/sync.yml b/.github/workflows/sync.yml
new file mode 100644
index 00000000..041339cd
--- /dev/null
+++ b/.github/workflows/sync.yml
@@ -0,0 +1,37 @@
+# This workflow will do a clean install of node dependencies, cache/restore them, build the source code and run tests across different versions of node
+# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
+
+name: Node.js CI
+
+on:
+ push:
+ branches: [ master ]
+
+jobs:
+ build:
+
+ runs-on: ubuntu-latest
+
+ env:
+ CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
+
+ strategy:
+ matrix:
+ node-version: [12.x]
+ # See supported Node.js release schedule at https://nodejs.org/en/about/releases/
+
+ steps:
+ - uses: actions/checkout@v2
+ - name: Use Node.js ${{ matrix.node-version }}
+ uses: actions/setup-node@v2
+ with:
+ node-version: ${{ matrix.node-version }}
+ - run: |
+ cd web
+ npm install
+ npm run crowdin:sync
+
+ - uses: stefanzweifel/git-auto-commit-action@v4
+ with:
+ commit_message: Sync from crowdin
+ file_pattern: web/src/locales/*
diff --git a/web/crowdin.yml b/web/crowdin.yml
new file mode 100644
index 00000000..6114b40b
--- /dev/null
+++ b/web/crowdin.yml
@@ -0,0 +1,10 @@
+project_id: '463556'
+api_token_env: 'CROWDIN_PERSONAL_TOKEN'
+preserve_hierarchy: true
+files: [
+ # JSON translation files
+ {
+ source: '/src/locales/en/**/*',
+ translation: '/src/locales/%two_letters_code%/**/%original_file_name%',
+ },
+ ]
diff --git a/web/package.json b/web/package.json
index 34d0ecae..c405fc47 100644
--- a/web/package.json
+++ b/web/package.json
@@ -5,6 +5,7 @@
"dependencies": {
"@ant-design/icons": "^4.6.2",
"@craco/craco": "^6.1.1",
+ "@crowdin/cli": "^3.6.2",
"@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.3.2",
"@testing-library/user-event": "^7.1.2",
@@ -30,7 +31,8 @@
"start": "cross-env PORT=7001 craco start",
"build": "craco build",
"test": "craco test",
- "eject": "craco eject"
+ "eject": "craco eject",
+ "crowdin:sync": "crowdin upload && crowdin download"
},
"eslintConfig": {
"extends": "react-app"
diff --git a/web/src/SelectLanguageBox.js b/web/src/SelectLanguageBox.js
index dfc36017..bb4d19e3 100644
--- a/web/src/SelectLanguageBox.js
+++ b/web/src/SelectLanguageBox.js
@@ -36,6 +36,31 @@ class SelectLanguageBox extends React.Component {
Setting.changeLanguage("zh")} className="lang-selector">
简体中文
+ /
+ {/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
+ Setting.changeLanguage("fr")} className="lang-selector">
+ Français
+
+ /
+ {/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
+ Setting.changeLanguage("de")} className="lang-selector">
+ Deutsch
+
+ /
+ {/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
+ Setting.changeLanguage("ja")} className="lang-selector">
+ 日本語
+
+ /
+ {/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
+ Setting.changeLanguage("ko")} className="lang-selector">
+ 한국어
+
+ /
+ {/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
+ Setting.changeLanguage("ru")} className="lang-selector">
+ Русский
+
)
diff --git a/web/src/i18n.js b/web/src/i18n.js
index f81562ee..2805a9fb 100644
--- a/web/src/i18n.js
+++ b/web/src/i18n.js
@@ -13,12 +13,22 @@
// limitations under the License.
import i18n from 'i18next'
-import zh from './locales/zh.json'
-import en from './locales/en.json'
+import zh from './locales/zh/data.json'
+import en from './locales/en/data.json'
+import fr from './locales/fr/data.json'
+import de from './locales/de/data.json'
+import ko from './locales/ko/data.json'
+import ru from './locales/ru/data.json'
+import ja from './locales/ja/data.json'
const resources = {
en: en,
- zh: zh
+ zh: zh,
+ fr: fr,
+ ja: ja,
+ de: de,
+ ko: ko,
+ ru: ru,
};
i18n
diff --git a/web/src/locales/en.json b/web/src/locales/en/data.json
similarity index 100%
rename from web/src/locales/en.json
rename to web/src/locales/en/data.json
diff --git a/web/src/locales/zh.json b/web/src/locales/zh.json
deleted file mode 100644
index c602689c..00000000
--- a/web/src/locales/zh.json
+++ /dev/null
@@ -1,252 +0,0 @@
-{
- "general":
- {
- "Home": "主页",
- "Home - Tooltip": "应用的首页",
- "Organizations": "组织",
- "Organizations - Tooltip": "Unique string-style identifier",
- "Organization": "组织",
- "Organization - Tooltip": "Unique string-style identifier",
- "Providers": "提供商",
- "Providers - Tooltip": "第三方登录需要配置的提供方",
- "Users": "用户",
- "User": "用户",
- "Applications": "应用",
- "Application": "应用",
- "Save": "保存",
- "Add": "添加",
- "Action": "操作",
- "Edit": "修改",
- "Delete": "删除",
- "Up": "上移",
- "Down": "下移",
- "Created time": "创建时间",
- "Name": "名称",
- "Name - Tooltip": "唯一的、字符串式的ID",
- "Display name": "显示名称",
- "Display name - Tooltip": "可重复的、仅作展示用途的ID",
- "Personal name": "姓名",
- "Personal name - Tooltip": "个人姓名",
- "Avatar": "头像",
- "Avatar - Tooltip": "向其他人展示的头像",
- "Default avatar": "默认头像",
- "Default avatar - Tooltip": "默认头像",
- "URL": "链接",
- "URL - Tooltip": "可访问的在线地址",
- "Preview": "预览",
- "Preview - Tooltip": "预览",
- "User type": "用户类型",
- "User type - Tooltip": "具有不同权限的用户角色",
- "Password type": "密码类型",
- "Password type - Tooltip": "密码在数据库中存储的形式",
- "Password salt": "密码Salt值",
- "Password salt - Tooltip": "用于密码加密的随机参数",
- "Password": "密码",
- "Email": "电子邮箱",
- "Phone": "手机号",
- "Logo": "图标",
- "Logo - Tooltip": "应用程序向外展示的图标",
- "User containers": "用户容器",
- "Users under all organizations": "所有组织里的用户",
- "OAuth providers": "OAuth提供方",
- "Applications that requires authentication": "需要鉴权的应用",
- "Swagger": "API总览",
- "Phone Prefix": "手机号前缀",
- "Enter the code": "输入验证码",
- "Captcha": "人机验证码",
- "Authorization code": "授权码",
- "Access token": "访问令牌",
- "Expires in": "有效期",
- "Scope": "范围",
- "Description": "Description",
- "Description - Tooltip": "与此有关的描述信息",
- "Token expire": "Token expire",
- "Token expire - Tooltip": "签发的令牌的授权时间",
- "Forget URL": "Forget URL",
- "Forget URL - Tooltip": "Forget URL - Tooltip",
- "Affiliation URL": "Affiliation URL",
- "Affiliation URL - Tooltip": "Affiliation URL - Tooltip",
- "Signup URL": "注册地址",
- "Signup URL - Tooltip": "展示给用户的注册地址",
- "Signin URL": "登录地址",
- "Signin URL - Tooltip": "用户的登录地址",
- "ID - Tooltip": "唯一的随机字符串",
- "Favicon - Tooltip": "网站的图标"
- },
- "signup":
- {
- "Username": "用户名",
- "Please input your display name!": "请输入您的显示名称!",
- "Please input your personal name!": "请输入您的姓名!",
- "Please input your address!": "请输入您的地址!",
- "Please input your affiliation!": "请输入您所在的工作单位!",
- "The input is not valid Email!": "您输入的电子邮箱格式错误!",
- "Please input your Email!": "请输入您的电子邮箱!",
- "Confirm": "确认密码",
- "Please confirm your password!": "请再次确认您的密码!",
- "Your confirmed password is inconsistent with the password!": "您两次输入的密码不一致!",
- "Please input your phone number!": "请输入您的手机号码!",
- "Accept": "阅读并接受",
- "Terms of Use": "《用户协议》",
- "Have account?": "已有账号?",
- "sign in now": "立即登录",
- "Your account has been created!": "您的账号已创建!",
- "Please click the below button to sign in": "请点击下方按钮登录",
- "Missing parameter.": "缺少参数"
- },
- "code":
- {
- "Please input your verification code!": "请输入您的验证码",
- "Verify code": "验证码",
- "Enter your code": "输入你的验证码",
- "You can only send one code in 60s.": "每分钟你只能发送一次验证码",
- "Code has not been sent yet!": "你还没有发送验证码",
- "You should verify your code in 5 min!": "验证码已超时。你应该在 5 分钟内完成验证。",
- "Wrong code!": "验证码错误!",
- "Code You Received": "验证码",
- "Empty Code": "验证码为空",
- "Send Code": "发送验证码",
- "code sent": "验证码已发送",
- "Email code": "邮箱验证码",
- "Phone code": "手机验证码",
- "PhoneCode has not been sent yet!": "尚未发送验证码至手机",
- "EmailCode has not been sent yet!": "尚未发送验证码至邮箱",
- "PhoneYou should verify your code in 10 min!": "你应该在 10 分钟之内验证手机号",
- "EmailYou should verify your code in 10 min!": "你应该在 10 分钟之内验证邮箱",
- "PhoneWrong code!": "手机验证码错误",
- "EmailWrong code!": "邮箱验证码错误",
- "Missing parameter.": "缺少参数",
- "Submit and complete": "完成提交"
- },
- "login":
- {
- "Please input your username, Email or phone!": "请输入您的用户名、Email或手机号!",
- "username, Email or phone": "用户名、Email或手机号",
- "Please input your password!": "请输入您的密码!",
- "Password": "密码",
- "Auto login": "下次自动登录",
- "Forgot password?": "忘记密码?",
- "Sign In": "登录",
- "No account yet?": "没有账号?",
- "sign up now": "立即注册",
- "To access": "访问",
- "Sign in with {type}": "{type}登录"
- },
- "account":
- {
- "My Account": "我的账户",
- "Settings for your account": "账户设置选项",
- "Login": "登录",
- "Logout": "登出",
- "Sign Up": "注册"
- },
- "organization":
- {
- "Edit Organization": "修改组织",
- "Website URL": "网页地址"
- },
- "provider":
- {
- "Name": "名称",
- "Display name": "显示名称",
- "Category": "分类",
- "Type": "类型",
- "Client ID": "Client ID",
- "Client secret": "Client secret",
- "Host": "主机",
- "Port": "端口号",
- "Email Title": "邮件标题",
- "Email Content": "邮件内容",
- "Region ID": "地域ID",
- "Sign Name": "签名名称",
- "Template Code": "模板CODE",
- "Provider URL": "提供商URL",
- "Edit Provider": "修改提供商"
- },
- "user":
- {
- "Edit User": "修改用户",
- "Upload a photo": "上传头像",
- "Select a photo...": "选择图片...",
- "Set new profile picture": "设置新头像",
- "Set password...": "设置密码...",
- "Modify password...": "修改密码...",
- "Address": "地址",
- "Affiliation": "工作单位",
- "Modify affiliation": "修改工作单位",
- "Tag": "标签",
- "Third-party logins": "第三方登录",
- "Properties": "属性",
- "Link": "绑定",
- "Unlink": "解绑",
- "Is admin": "是管理员",
- "Is global admin": "是全局管理员",
- "Is forbidden": "被禁用",
- "Empty input!": "输入为空!",
- "Two passwords you typed do not match.": "两次输入的密码不匹配。",
- "Password Set": "密码已设置",
- "Set Password": "设置密码",
- "Old Password": "旧密码",
- "New Password": "新密码",
- "Re-enter New": "重复新密码",
- "Please login first.": "请先登录。",
- "Session outdated. Please login again.": "会话已过期,请重新登陆。",
- "Invalid user id.": "用户 ID 错误",
- "You don't have the permission to do this.": "你没有权限这么做。",
- "Old password wrong.": "旧密码错误!",
- "New password contains blank space.": "新密码包含空格。",
- "Invalid new password": "非法的新密码。",
- "Password": "密码",
- "OK": "确定",
- "Cancel": "取消",
- "input password": "输入密码",
- "Reset Email...": "重置邮箱...",
- "Reset Phone...": "重置手机号...",
- "Empty email": "邮箱为空",
- "Empty phone": "手机号为空",
- "phone reset": "手机号已设置",
- "email reset": "邮箱已设置",
- "Input your email": "请输入邮箱",
- "Input your phone number": "输入手机号",
- "New phone": "新手机号",
- "New email": "新邮箱",
- "Invalid phone number": "手机号格式错误",
- "Invalid Email address": "邮箱格式错误",
- "Turing test failed.": "图灵验证失败,无法确认你是人类!",
- "Missing parameter.": "缺少参数!请确认所有信息都已填写!"
- },
- "application":
- {
- "Edit Application": "修改应用",
- "Enable password": "开启密码",
- "Login page preview": "登录页面预览",
- "Test signup page..": "测试注册页面..",
- "Test signin page..": "测试登录页面..",
- "Test prompt page..": "测试提醒页面..",
- "Redirect URL": "回调URL",
- "Redirect URLs": "回调URLs",
- "Signup items": "注册项"
- },
- "forget":
- {
- "Please input your application!": "请输入您的应用名称!",
- "Please input your organization!": "请输入您的组织名称!",
- "Unknown forgot type:": "未知的忘记类型:",
- "Please input your username!": "请输入您的用户名!",
- "Please input your password!": "请输入您的密码!",
- "Please confirm your password!": "请确认您的密码!",
- "Please input your Email/Phone string!": "请输入您的邮箱/手机号!",
- "Your confirmed password is inconsistent with the password!": "您确认的密码与密码不一致!",
- "Password": "密码",
- "Next Step": "下一步",
- "Choose email verification or mobile verification": "选择邮箱验证或手机验证",
- "Retrieve password": "找回密码",
- "Confirm": "验证密码",
- "Email/Phone's format wrong!": "邮箱/手机号格式错误!",
- "Change Password": "修改密码",
- "Account": "账号",
- "Email/Phone": "邮箱/手机号",
- "Verify": "验证",
- "Reset": "重置"
- }
-}