From dcf85591e29ec98d1b65d9bab63bfb9e8792b7ca Mon Sep 17 00:00:00 2001 From: ErikQQY <2283984853@qq.com> Date: Sat, 3 Jul 2021 10:09:29 +0800 Subject: [PATCH] feat: Integrate Crowdin Signed-off-by: ErikQQY <2283984853@qq.com> --- .github/workflows/sync.yml | 37 ++++ web/crowdin.yml | 10 + web/package.json | 4 +- web/src/SelectLanguageBox.js | 25 +++ web/src/i18n.js | 16 +- web/src/locales/{en.json => en/data.json} | 0 web/src/locales/zh.json | 252 ---------------------- 7 files changed, 88 insertions(+), 256 deletions(-) create mode 100644 .github/workflows/sync.yml create mode 100644 web/crowdin.yml rename web/src/locales/{en.json => en/data.json} (100%) delete mode 100644 web/src/locales/zh.json 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": "重置" - } -}