diff --git a/frontend/.eslintrc.json b/frontend/.eslintrc.json index 0c5504b90..821ea5f1f 100644 --- a/frontend/.eslintrc.json +++ b/frontend/.eslintrc.json @@ -4,6 +4,7 @@ "simple-import-sort" ], "rules": { + "i18n-ally-translation-missing": "off", "react-hooks/exhaustive-deps": "off", "simple-import-sort/exports": "warn", "simple-import-sort/imports": [ diff --git a/frontend/.vscode/settings.json b/frontend/.vscode/settings.json new file mode 100644 index 000000000..c4742cc40 --- /dev/null +++ b/frontend/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "i18n-ally.localesPaths": [ + "locales", + "public/locales" + ] +} \ No newline at end of file diff --git a/frontend/components/basic/dialog/AddIncidentContactDialog.js b/frontend/components/basic/dialog/AddIncidentContactDialog.js index fad13cdee..28c6ee968 100644 --- a/frontend/components/basic/dialog/AddIncidentContactDialog.js +++ b/frontend/components/basic/dialog/AddIncidentContactDialog.js @@ -1,4 +1,5 @@ import { Fragment, useState } from "react"; +import useTranslate from "next-translate/useTranslation"; import { Dialog, Transition } from "@headlessui/react"; import addIncidentContact from "~/pages/api/organization/addIncidentContact"; @@ -14,6 +15,7 @@ const AddIncidentContactDialog = ({ setIncidentContacts, }) => { let [incidentContactEmail, setIncidentContactEmail] = useState(""); + const { t } = useTranslate(); const submit = () => { setIncidentContacts( @@ -59,17 +61,16 @@ const AddIncidentContactDialog = ({ as="h3" className="text-lg font-medium leading-6 text-gray-400" > - Add an Incident Contact + {t("section-incident:add-dialog.title")}

- This contact will be notified in the unlikely event of a - severe incident. + {t("section-incident:add-dialog.description")}

diff --git a/frontend/components/basic/dialog/AddProjectMemberDialog.js b/frontend/components/basic/dialog/AddProjectMemberDialog.js index 32cfb41cc..be875d65c 100644 --- a/frontend/components/basic/dialog/AddProjectMemberDialog.js +++ b/frontend/components/basic/dialog/AddProjectMemberDialog.js @@ -52,25 +52,25 @@ const AddProjectMemberDialog = ({ as="h3" className="text-lg font-medium leading-6 text-gray-400 z-50" > - {t("settings:add-member-dialog.add-member-to-project")} + {t("section-members:add-dialog.add-member-to-project")} ) : ( - {t("settings:add-member-dialog.already-all-invited")} + {t("section-members:add-dialog.already-all-invited")} )}
{data?.length > 0 ? (

- {t("settings:add-member-dialog.user-will-email")} + {t("section-members:add-dialog.user-will-email")}

- click here. - , + />, ]} />
) : (

- {t("settings:add-member-dialog.add-user-org-first")} + {t("section-members:add-dialog.add-user-org-first")}

)}
@@ -122,7 +120,7 @@ const AddProjectMemberDialog = ({ - Click to Copy + {t("common.click-to-copy")} diff --git a/frontend/i18n.js b/frontend/i18n.js index 901b5317b..4390cab6b 100644 --- a/frontend/i18n.js +++ b/frontend/i18n.js @@ -1,16 +1,27 @@ const workaround = require("next-translate/lib/cjs/plugin/utils.js"); workaround.defaultLoader = - "(l, n) => import(`@next-translate-root/locales/${l}.json`).then(m => m?.default[n] ?? {} )"; + "(l, n) => import(`@next-translate-root/locales/${l}.json`).then(m => m?.default[n] ?? {} )"; module.exports = { - locales: ["en-US", "ko-KR"], - defaultLocale: "en-US", - pages: { - "*": ["common", "nav"], - "rgx:^/(login|signup)": ["auth"], - "rgx:^/settings": ["settings"], - "/dashboard/[id]": ["dashboard"], - "/users/[id]": ["settings"], - }, + locales: ["en-US", "ko-KR"], + defaultLocale: "en-US", + pages: { + "*": ["common", "nav"], + "/login": ["login"], + "/signup": ["signup", "form-password"], + "rgx:^/(login|signup)": ["auth"], + "rgx:^/settings": ["settings"], + "/dashboard/[id]": ["dashboard"], + "/users/[id]": ["settings-members", "section-members"], + "/settings/project/[id]": ["settings-project", "section-token"], + "/settings/org/[id]": [ + "settings-org", + "section-incident", + "section-members", + ], + "/settings/personal/[id]": ["settings-personal"], + "/settings/billing/[id]": ["billing"], + "/integrations/[id]": ["integrations"], + }, }; diff --git a/frontend/locales/en-US.json b/frontend/locales/en-US.json index 0dbc405fc..c360c4a49 100644 --- a/frontend/locales/en-US.json +++ b/frontend/locales/en-US.json @@ -1,18 +1,15 @@ { "common": { + "head-title": "{{title}} | Infiscal", "error_project-already-exists": "A project with this name already exists.", "no-mobile": " To use Infisical, please log in through a device with larger dimensions. ", "email": "Email", "password": "Password", - "verify": "Verify", "first-name": "First Name", "last-name": "Last Name", "logout": "Log Out", "validate-required": "Please input your {{name}}", - "password-validate": "Password should contain at least:", - "password-validate-length": "14 characters", - "password-validate-case": "1 lowercase character", - "password-validate-number": "1 number", + "maintenance-alert": "We are experiencing minor technical difficulties. We are working on solving it right now. Please come back in a few minutes.", "click-to-copy": "Click to copy", "project-id": "Project ID", @@ -22,7 +19,29 @@ "drop-zone-keys": "Drag and drop your .env file here to add more keys.", "role": "Role", "role_admin": "admin", - "display-name": "Display Name" + "display-name": "Display Name", + "free": "Free", + "starter": "Starter", + "professional": "Professional", + "enterprise": "Enterprise", + "downgrade": "Downgrade", + "upgrade": "Upgrade", + "learn-more": "Learn More", + "custom-pricing": "Custom Pricing", + "schedule-demo": "Schedule a Demo", + "environment": "Environment", + "expired-in": "Expires in" + }, + "form-password": { + "password": "Password", + "change": "Change password", + "current": "Current password", + "current-wrong": "The current password may be wrong", + "new": "New password", + "validate-base": "Password should contain at least:", + "validate-length": "14 characters", + "validate-case": "1 lowercase character", + "validate-number": "1 number" }, "nav": { "support": { @@ -46,25 +65,22 @@ "project-settings": "Project Settings" } }, - "auth": { - "meta": { - "login": { - "title": "Login | Infiscal", - "og-title": "Log In to Infisical", - "og-description": "Infisical a simple end-to-end encrypted platform that enables teams to sync and manage their .env files." - }, - "signup": { - "title": "Sign Up | Infiscal", - "og-title": "Replace .env files with 1 line of code. Sign Up for Infisical in 3 minutes.", - "og-description": "Infisical a simple end-to-end encrypted platform that enables teams to sync and manage API-keys and environemntal variables. Works with Node.js, Next.js, Gatsby, Nest.js..." - } - }, + "login": { + "title": "Login", + "og-title": "Log In to Infisical", + "og-description": "Infisical a simple end-to-end encrypted platform that enables teams to sync and manage their .env files.", "login": "Log In", - "signup": "Sign Up", "need-account": "Need an Infisical account?", - "create-account": "Create an account", + "create-account": "Create an account" + }, + "signup": { + "title": "Sign Up", + "og-title": "Replace .env files with 1 line of code. Sign Up for Infisical in 3 minutes.", + "og-description": "Infisical a simple end-to-end encrypted platform that enables teams to sync and manage API-keys and environemntal variables. Works with Node.js, Next.js, Gatsby, Nest.js...", + "signup": "Sign Up", "already-have-account": "Have an account? Log in", "forgot-password": "Forgot your password?", + "verify": "Verify", "step1-start": "Let's get started", "step1-privacy": "By creating an account, you agree to our Terms and have read and acknowledged the Privacy Policy.", "step1-submit": "Get Started", @@ -100,36 +116,105 @@ "line2": "Here is how to connect them to your codebase." } }, + "settings-members": { + "title": "Project Members", + "description": "This pages shows the members of the selected project." + }, + "settings-org": { + "title": "Organization Settings", + "description": "Manage members of your organization. These users could afterwards be formed into projects." + }, + "settings-personal": { + "title": "Personal Settings", + "description": "View and manage your personal information here.", + "emergency": { + "name": "Emergency Kit", + "text1": "Your Emergency Kit contains the information you’ll need to sign in to your Infisical account.", + "text2": "Only the latest issued Emergency Kit remains valid. To get a new Emergency Kit, verify your password.", + "download": "Download Emergency Kit" + } + }, + "settings-project": { + "title": "Project Settings", + "description": "These settings only apply to the currently selected Project.", + "danger-zone": "Danger Zone", + "delete-project": "Delete Project", + "project-to-delete": "Project to be Deleted", + "danger-zone-note": "As soon as you delete this project, you will not be able to undo it. This will immediately remove all the keys. If you still want to do that, please enter the name of the project below.", + "delete-project-note": "Note: You can only delete a project in case you have more than one", + "project-id-description": "To integrate Infisical into your code base and get automatic injection of environmental variables, you should use the following Project ID.", + "project-id-description2": "For more guidance, including code snipets for various languages and frameworks, see ", + "auto-generated": "This is your project's auto-generated unique identifier. It can't be changed.", + "docs": "Infisical Docs" + }, + "section-token": { + "service-tokens": "Service Tokens", + "service-tokens-description": "Every service token is specific to you, a certain project and a certain environment within this project.", + "add-new": "Add New Token", + "add-dialog": { + "title": "Add a service token for {{target}}", + "description": "Specify the name, environment, and expiry period. When a token is generated, you will only be able to see it once before it disappears. Make sure to save it somewhere.", + "name": "Service Token Name", + "add": "Add Service Token", + "copy-service-token": "Copy your service token", + "copy-service-token-description": "Once you close this popup, you will never see your service token again" + } + }, "settings": { - "meta": { - "members": { - "title": "Project Members", - "head-title": "Project Settings | Infiscal", - "description": "This pages shows the members of the selected project." - }, - "org": { - "title": "Organization Settings", - "head-title": "Organization Settings | Infiscal", - "description": "Manage members of your organization. These users could afterwards be formed into projects." - } - }, - "search-members": "Search members...", "search": "Search...", + "delete-project": "Delete Project" + }, + "billing": { + "title": "Usage & Billing", + "description": "View and manage your organization's subscription here", + "subscription": "Subscription", + "starter": { + "price-explanation": "up to 5 team members", + "text": "Manage any project with 5 members for free!", + "subtext": "$5 per member/month afterwards." + }, + "professional": { + "price-explanation": "/member/month", + "subtext": "Includes unlimited projects & members.", + "text": "Keep up with key management as you grow." + }, + "enterprise": { + "text": "Keep up with key management as you grow." + }, + "current-usage": "Current Usage" + }, + "section-members": { "add-member": "Add Member", "org-members": "Organization Members", "org-members-description": "Manage members of your organization. These users could afterwards be formed into projects.", - "incident-contacts": "Incident Contacts", - "incident-contacts-description": "These contacts will be notified in the unlikely event of a severe incident.", - "no-incident-contacts": "No incident contacts found.", - "add-contact": "Add Contact", - "add-member-dialog": { + "search-members": "Search members...", + "add-dialog": { "add-member-to-project": "Add a member to your project", "already-all-invited": "All the users in your organization are already invited.", "add-user-org-first": "Add more users to the organization first.", "user-will-email": "The user will receive an email with the instructions.", "looking-add": "<0>If you are looking to add users to your org,<1>click here", - "add-user-to-org": "Add Users to Organization", - "add-member": "Add Member" + "add-user-to-org": "Add Users to Organization" } + }, + "section-incident": { + "incident-contacts": "Incident Contacts", + "incident-contacts-description": "These contacts will be notified in the unlikely event of a severe incident.", + "no-incident-contacts": "No incident contacts found.", + "add-contact": "Add Contact", + "add-dialog": { + "title": "Add an Incident Contact", + "description": "This contact will be notified in the unlikely event of a severe incident.", + "add-incident": "Add Incident Contact" + } + }, + "integrations": { + "title": "Project Integrations", + "description": "Manage your integrations of Infisical with third-party services.", + "no-integrations1": "You don't have any integrations set up yet. When you do, they will appear here.", + "no-integrations2": "To start, click on any of the options below. It takes 5 clicks to set up.", + "available": "Available Integrations", + "available-text1": "Click on the itegration you want to connect. This will let your environment variables flow automatically into selected third-party services.", + "available-text2": " Note: during an integration with Heroku, for security reasons, it is impossible to maintain end-to-end encryption. In theory, this lets Infisical decrypt yor environment variables. In practice, we can assure you that this will never be done, and it allows us to protect your secrets from bad actors online. The core Infisical service will always stay end-to-end encrypted. With any questions, reach out support@infisical.com." } } diff --git a/frontend/locales/ko-KR.json b/frontend/locales/ko-KR.json index 262751a29..b8bba2e77 100644 --- a/frontend/locales/ko-KR.json +++ b/frontend/locales/ko-KR.json @@ -1,6 +1,189 @@ { - "common": {}, - "nav": {}, - "auth": {}, - "dashboard": {} + "common": { + "head-title": "{{title}} | Infiscal", + "error_project-already-exists": "A project with this name already exists.", + "no-mobile": " To use Infisical, please log in through a device with larger dimensions. ", + "email": "Email", + "password": "Password", + "first-name": "First Name", + "last-name": "Last Name", + "logout": "Log Out", + "validate-required": "Please input your {{name}}", + "maintenance-alert": "We are experiencing minor technical difficulties. We are working on solving it right now. Please come back in a few minutes.", + "click-to-copy": "Click to copy", + "project-id": "Project ID", + "project-id-description": "To integrate Infisical into your code base and get automatic injection of environmental variables, you should use the following Project ID.", + "save-changes": "Save Changes", + "saved": "Saved", + "drop-zone": "Drag and drop your .env file here.", + "drop-zone-keys": "Drag and drop your .env file here to add more keys.", + "role": "Role", + "role_admin": "admin", + "display-name": "Display Name", + "free": "Free", + "starter": "Starter", + "professional": "Professional", + "enterprise": "Enterprise", + "downgrade": "Downgrade", + "upgrade": "Upgrade", + "learn-more": "Learn More", + "custom-pricing": "Custom Pricing", + "schedule-demo": "Schedule a Demo" + }, + "form-password": { + "password": "비밀번호", + "change": "비밀번호 변경", + "current": "현재 비밀번호", + "new": "새 비밀번호", + "current-wrong": "현재 비밀번호가 잘못되었어요", + "validate-base": "비밀번호는 다음 조건을 만족해야 합니다:", + "validate-length": "14 글자 이상", + "validate-case": "1개 이상의 소문자", + "validate-number": "1개 이상의 숫자" + }, + "nav": { + "support": { + "slack": "[NEW] 슬랙 포럼에 가입하기", + "docs": "문서 보기", + "issue": "깃허브 이슈 열기", + "email": "Infisical팀에게 메일 보내기" + }, + "user": { + "signed-in-as": "다음으로 로그인됨", + "current-organization": "현재 조직", + "usage-billing": "요금제 & 결제", + "invite": "맴버 초대하기", + "other-organizations": "다른 조직" + }, + "menu": { + "project": "프로젝트", + "secrets": "시크릿", + "members": "맴버", + "integrations": "연동", + "project-settings": "프로젝트 설정" + } + }, + "login": { + "title": "로그인", + "og-title": "Infisical에 로그인하기", + "og-description": "Infisical a simple end-to-end encrypted platform that enables teams to sync and manage their .env files.", + "login": "로그인", + "need-account": "Infisical계정이 필요하신가요?", + "create-account": "회원가입 하기" + }, + "signup": { + "title": "회원가입", + "og-title": "Replace .env files with 1 line of code. Sign Up for Infisical in 3 minutes.", + "og-description": "Infisical a simple end-to-end encrypted platform that enables teams to sync and manage API-keys and environemntal variables. Works with Node.js, Next.js, Gatsby, Nest.js...", + "signup": "회원가입", + "already-have-account": "Have an account? Log in", + "forgot-password": "Forgot your password?", + "verify": "인증", + "step1-start": "시작하기", + "step1-privacy": "회원가입시 약관과 개인 정보 보호 정책을 읽고 동의한 것으로 간주합니다.", + "step1-submit": "시작하기", + "step2-message": "{{email}}로 인증 메일을 전송하였습니다{{email}}", + "step2-code-error": "코드가 잘못된 것 같아요. 다시 시도해주세요.", + "step2-spam-alert": "스팸함에 메일이 있지는 않은지 확인하세요", + "step3-message": "거의다 끝났어요!", + "step4-message": "긴급복구 키트 저장하기", + "step4-description1": "계정이 잠겼을 경우 비상 키트를 사용하여 로그인할 수 있어요.", + "step4-description2": "다운로드 후 안전한 곳에 보관하는 것을 추천합니다.", + "step4-description3": "분실시 접근하거나 복구할 수 없는 시크릿 키가 포함되어 있어요.", + "step4-download": "PDF 다운로드" + }, + "dashboard": { + "secrets": "시크릿", + "meta": { + "title": "Dashboard | Infiscal", + "og-title": "Manage your .env files in seconds", + "og-description": "Infisical a simple end-to-end encrypted platform that enables teams to sync and manage their .env files." + }, + "search-keys": "Search keys...", + "add-key": "Add Key", + "personal": "Personal", + "personal-description": "Personal keys are only visible to you", + "shared": "Shared", + "shared-description": "Shared keys are visible to your whole team", + "make-shared": "Make Shared", + "make-personal": "Make Personal", + "check-docs": { + "button": "Check Docs", + "title": "Good job!", + "line1": "Congrats on adding more secrets.", + "line2": "Here is how to connect them to your codebase." + } + }, + "settings-members": { + "title": "맴버 설정", + "description": "선택한 프로젝트의 맴버를 확인하세요." + }, + "settings-org": { + "title": "조직 설정", + "description": "조직의 맴버를 관리하세요." + }, + "settings-personal": { + "title": "개인 설정", + "description": "계정 및 기본적인 설정을 확인하고 변경하세요.", + "emergency": { + "name": "긴급복구 키트", + "text1": "긴급복구 키트는 Infisical계정에 로그인 할 수 있는 정보를 가지고 있어요.", + "text2": "오직 마지막으로 발급한 긴급복구 키트만 사용 가능해요. 새로운 긴급복구 키트를 받으려면, 비밀번호를 입력하세요.", + "download": "긴급복구 키트 다운로드" + } + }, + "settings-project": { + "title": "프로젝트 설정", + "description": "현재 선택한 프로젝트에 대해서만 설정해요." + }, + "settings": { + "search-members": "Search members...", + "search": "Search...", + "add-member": "Add Member", + "org-members": "Organization Members", + "org-members-description": "Manage members of your organization. These users could afterwards be formed into projects.", + "incident-contacts": "Incident Contacts", + "incident-contacts-description": "These contacts will be notified in the unlikely event of a severe incident.", + "no-incident-contacts": "No incident contacts found.", + "add-contact": "Add Contact", + "delete-project": "Delete Project", + "delete-project-note": "Note: You can only delete a project in case you have more than one", + "project-danger-zone-note": "As soon as you delete this project, you will not be able to undo it. This will immediately remove all the keys. If you still want to do that, please enter the name of the project below.", + "danger-zone": "Danger Zone", + "service-tokens": "Service Tokens", + "service-tokens-description": "Every service token is specific to you, a certain project and a certain environment within this project." + }, + "billing": { + "title": "요금제 & 결제", + "description": "이곳에서 조직의 구독을 확인하고 관리할 수 있어요.", + "subscription": "구독", + "starter": { + "price-explanation": "5명의 팀 맴버까지", + "text": "어떤 프로젝트든 다섯명의 맴버까지 무료로 이용할 수 있어요!", + "subtext": "$5명/달 로 바뀔 예정입니다." + }, + "professional": { + "price-explanation": "/맴버/달", + "subtext": "무제한의 프로젝트와 맴버", + "text": "조직의 성장에 따라 유연하게 시크릿을 관리하세요." + }, + "enterprise": { + "text": "조직의 성장에 따라 유연하게 시크릿을 관리하세요." + }, + "current-usage": "현재 요금제" + }, + "section-members": { + "add-member": "맴버 추가하기", + "org-members": "조직 맴버", + "search-members": "맴버를 검색하기...", + "add-dialog": { + "add-member-to-project": "프로젝트에 맴버 추가하기", + "already-all-invited": "조직의 모든 유저가 이미 초대되었습니다.", + "add-user-org-first": "유저를 먼저 조직에 추가해 주세요.", + "user-will-email": "유저는 안내가 포함된 메일을 받게 됩니다.", + "looking-add": "<0>조직에 유저를 추가하고 싶다면,<1>여기를 클릭하세요", + "add-user-to-org": "조직에 유저 추가하기" + } + }, + "integrations": {} } diff --git a/frontend/next.config.js b/frontend/next.config.js index 3cf7273f6..429c91c49 100644 --- a/frontend/next.config.js +++ b/frontend/next.config.js @@ -65,4 +65,7 @@ module.exports = nextTranslate({ }, ]; }, + webpack: (config, { isServer, webpack }) => { + return config; + }, }); diff --git a/frontend/pages/integrations/[id].js b/frontend/pages/integrations/[id].js index 3689c24ff..aa9dd8412 100644 --- a/frontend/pages/integrations/[id].js +++ b/frontend/pages/integrations/[id].js @@ -2,6 +2,7 @@ import React, { useEffect, useState } from "react"; import Head from "next/head"; import Image from "next/image"; import { useRouter } from "next/router"; +import useTranslation from "next-translate/useTranslation"; import { faArrowRight, faCheck, @@ -54,6 +55,8 @@ const Integration = ({ projectIntegration }) => { projectIntegration.app ? projectIntegration.app : apps[0] ); + const { t } = useTranslation(); + useEffect(async () => { const tempHerokuApps = await getIntegrationApps({ integrationAuthId: projectIntegration.integrationAuth, @@ -179,6 +182,8 @@ export default function Integrations() { const router = useRouter(); const [csrfToken, setCsrfToken] = useState(""); + const { t } = useTranslation(); + useEffect(async () => { const tempCSRFToken = crypto.randomBytes(16).toString("hex"); setCsrfToken(tempCSRFToken); @@ -205,24 +210,28 @@ export default function Integrations() { return integrations ? (
- Dashboard + + <title> + {t("common:head-title", { title: t("integrations:title") })} + + - +
- +
-

Current Project Integrations

+

{t("integrations:title")}

- Manage your integrations of Infisical with third-party services. + {t("integrations:description")}

{projectIntegrations.length > 0 ? ( @@ -235,34 +244,22 @@ export default function Integrations() { ) : (
-
- You {"don't"} have any integrations set up yet. When you do, - they will appear here. -
-
- To start, click on any of the options below. It takes 5 clicks - to set up. -
+
{t("integrations:no-integrations1")}
+
{t("integrations:no-integrations2")}
)}
-

Available Integrations

+

+ {t("integrations:available")} +

- Click on the itegration you want to connect. This will let your - environment variables flow automatically into selected third-party - services. + {t("integrations:available-text1")}

- Note: during an integration with Heroku, for security reasons, it - is impossible to maintain end-to-end encryption. In theory, this - lets Infisical decrypt yor environment variables. In practice, we - can assure you that this will never be done, and it allows us to - protect your secrets from bad actors online. The core Infisical - service will always stay end-to-end encrypted. With any questions, - reach out support@infisical.com. + {t("integrations:available-text2")}

diff --git a/frontend/pages/login.js b/frontend/pages/login.js index eaa82628f..24f8d9e75 100644 --- a/frontend/pages/login.js +++ b/frontend/pages/login.js @@ -55,14 +55,11 @@ export default function Login() { return (
- {t("auth:meta.login.title")} + {t("common:head-title", { title: t("login:title") })} - - + +
@@ -76,18 +73,18 @@ export default function Login() {

- {t("auth:login")} + {t("login:login")}

- {t("auth:need-account")} + {t("login:need-account")}

@@ -116,7 +113,7 @@ export default function Login() {
)}
diff --git a/frontend/pages/settings/billing/[id].js b/frontend/pages/settings/billing/[id].js index 609648b9b..2be884f97 100644 --- a/frontend/pages/settings/billing/[id].js +++ b/frontend/pages/settings/billing/[id].js @@ -1,5 +1,6 @@ import React, { useEffect, useState } from "react"; import Head from "next/head"; +import useTranslation from "next-translate/useTranslation"; import Plan from "~/components/billing/Plan"; import NavHeader from "~/components/navigation/NavHeader"; @@ -12,36 +13,38 @@ export default function SettingsBilling() { let [currentPlan, setCurrentPlan] = useState(""); let [numUsers, setNumUsers] = useState(""); + const { t } = useTranslation(); + const plans = [ { key: 1, - name: "Starter", - price: "Free", - priceExplanation: "up to 5 team members", - text: "Manage any project with 5 members for free!", - subtext: "$5 per member/month afterwards.", - buttonTextMain: "Downgrade", - buttonTextSecondary: "Learn More", + name: t("common:starter"), + price: t("common:free"), + priceExplanation: t("billing:starter.price-explanation"), + text: t("billing:starter.text"), + subtext: t("billing:starter.subtext"), + buttonTextMain: t("common:downgrade"), + buttonTextSecondary: t("common:learn-more"), current: currentPlan == STRIPE_PRODUCT_STARTER, }, { key: 2, - name: "Professional", + name: t("common:professional"), price: "$9", - priceExplanation: "/member/month", - subtext: "Includes unlimited projects & members.", - text: "Keep up with key management as you grow.", - buttonTextMain: "Upgrade", - buttonTextSecondary: "Learn More", + priceExplanation: t("billing:professional.price-explanation"), + subtext: t("billing:professional.subtext"), + text: t("billing:professional.text"), + buttonTextMain: t("common:upgrade"), + buttonTextSecondary: t("common:learn-more"), current: currentPlan == STRIPE_PRODUCT_PRO, }, { key: 3, - name: "Enterprise", - price: "Custom Pricing", - text: "More control for advanced organizations.", - buttonTextMain: "Schedule a Demo", - buttonTextSecondary: "Learn More", + name: t("common:enterprise"), + price: t("common:custom-pricing"), + text: t("billing:enterprise.text"), + buttonTextMain: t("common:schedule-demo"), + buttonTextSecondary: t("common:learn-more"), current: false, }, ]; @@ -61,30 +64,32 @@ export default function SettingsBilling() { return (
- Settings - Billing + {t("common:head-title", { title: t("billing:title") })}
- +

- Usage & Billing + {t("billing:title")}

- View and manage your {"organization's"} subscription here. + {t("billing:description")}

-

Subscription

+

{t("billing:subscription")}

{plans.map((plan) => ( ))}
-

Current Usage

+

+ {t("billing:current-usage")} +

{numUsers}

diff --git a/frontend/pages/settings/org/[id].js b/frontend/pages/settings/org/[id].js index 89ac3ce0e..b09082a73 100644 --- a/frontend/pages/settings/org/[id].js +++ b/frontend/pages/settings/org/[id].js @@ -159,12 +159,14 @@ export default function SettingsOrg() { return (
- {t("settings:meta.org.head-title")} + + {t("common:head-title", { title: t("settings-org:title") })} +
- +

- {t("settings:meta.org.title")} + {t("settings-org:title")}

- {t("settings:meta.org.description")} + {t("settings-org:description")}

@@ -278,15 +280,15 @@ export default function SettingsOrg() {

- {t("settings:incident-contacts")} + {t("section-incident:incident-contacts")}

- {t("settings:incident-contacts-description")} + {t("section-incident:incident-contacts-description")}

)} diff --git a/frontend/pages/settings/personal/[id].js b/frontend/pages/settings/personal/[id].js index 928d426b0..04c6d57b6 100644 --- a/frontend/pages/settings/personal/[id].js +++ b/frontend/pages/settings/personal/[id].js @@ -1,5 +1,6 @@ import React, { useEffect, useState } from "react"; import Head from "next/head"; +import useTranslation from "next-translate/useTranslation"; import { faCheck, faX } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; @@ -26,6 +27,8 @@ export default function PersonalSettings() { const [backupKeyIssued, setBackupKeyIssued] = useState(false); const [backupKeyError, setBackupKeyError] = useState(false); + const { t } = useTranslation(); + useEffect(async () => { let user = await getUser(); setPersonalEmail(user.email); @@ -35,19 +38,24 @@ export default function PersonalSettings() { return (
- Personal Settings + + {t("common:head-title", { title: t("settings-personal:title") })} +
- +

- Personal Settings + {t("settings-personal:title")}

- View and manage your personal information here. + {t("settings-personal:description")}

@@ -104,13 +112,13 @@ export default function PersonalSettings() {

- Change password + {t("form-password:change")}

{ setCurrentPassword(password); }} @@ -118,11 +126,11 @@ export default function PersonalSettings() { value={currentPassword} isRequired error={currentPasswordError} - errorText="The current password may be wrong" + errorText={t("form-password:current-wrong")} />
{ setNewPassword(password); passwordCheck( @@ -148,7 +156,7 @@ export default function PersonalSettings() { passwordErrorNumber ? (
- Password should contain at least: + {t("form-password:validate-base")}
{passwordErrorLength ? ( @@ -167,7 +175,7 @@ export default function PersonalSettings() { passwordErrorLength ? "text-gray-400" : "text-gray-600" } text-sm`} > - 14 characters + {t("form-password:validate-length")}
@@ -189,7 +197,7 @@ export default function PersonalSettings() { : "text-gray-600" } text-sm`} > - 1 lowercase character + {t("form-password:validate-case")}
@@ -209,7 +217,7 @@ export default function PersonalSettings() { passwordErrorNumber ? "text-gray-400" : "text-gray-600" } text-sm`} > - 1 number + {t("form-password:validate-number")}
@@ -247,7 +255,7 @@ export default function PersonalSettings() { passwordErrorNumber ) } - textDisabled="Change Password" + textDisabled={t("password:change")} />

- Emergency Kit + {t("settings-personal:emergency.name")}

- Your Emergency Kit contains the information you’ll need to - sign in to your Infisical account. + {t("settings-personal:emergency.text1")}

- Only the latest issued Emergency Kit remains valid. To get a - new Emergency Kit, verify your password. + {t("settings-personal:emergency.text2")}

-

Project ID

+

+ {t("common:project-id")} +

- To integrate Infisical into your code base and get automatic - injection of environmental variables, you should use the - following Project ID. + {t("settings-project:project-id-description")}

- For more guidance, including code snipets for various - languages and frameworks, see{" "} + {t("settings-project:project-id-description2")} {/* eslint-disable-next-line react/jsx-no-target-blank */} - Infisical Docs. + {t("settings-project:docs")}

@@ -166,7 +175,7 @@ export default function SettingsBasic() { placeholder="" isRequired static - text="This is your project's auto-generated unique identifier. It can't be changed." + text={t("settings-project:auto-generated")} />
@@ -174,16 +183,15 @@ export default function SettingsBasic() {

- Service Tokens + {t("section-token:service-tokens")}

- Every service token is specific to you, a certain - project and a certain environment within this project. + {t("section-token:service-tokens-description")}

-

Danger Zone

+

+ {t("settings-project:danger-zone")} +

- As soon as you delete this project, you will not be able to undo - it. This will immediately remove all the keys. If you still want - to do that, please enter the name of the project below. + {t("settings-project:danger-zone-note")}

- Delete Project + {t("settings-project:delete-project")}

- Note: You can only delete a project in case you have more than - one. + {t("settings-project:delete-project-note")}

diff --git a/frontend/pages/signup.js b/frontend/pages/signup.js index e46c6eb20..6c3d0b0f0 100644 --- a/frontend/pages/signup.js +++ b/frontend/pages/signup.js @@ -250,13 +250,13 @@ export default function SignUp() { const step1 = (

- {t("auth:step1-start")} + {t("signup:step1-start")}

@@ -279,12 +279,11 @@ export default function SignUp() {
*/}

- By creating an account, you agree to our Terms and have read and - acknowledged the Privacy Policy. + {t("signup:step1-privacy")}

*/}

- {t("auth:step2-spam-alert")} + {t("signup:step2-spam-alert")}

@@ -352,7 +351,7 @@ export default function SignUp() { const step3 = (

- {t("auth:step3-message")} + {t("signup:step3-message")}

{ setPassword(password); passwordCheck( @@ -405,7 +404,7 @@ export default function SignUp() { passwordErrorNumber ? (
- {t("auth:password-validate")} + {t("form-password:validate-base")}
{passwordErrorLength ? ( @@ -424,7 +423,7 @@ export default function SignUp() { passwordErrorLength ? "text-gray-400" : "text-gray-600" } text-sm`} > - {t("auth:password-validate-length")} + {t("form-password:validate-length")}
@@ -444,7 +443,7 @@ export default function SignUp() { passwordErrorLowerCase ? "text-gray-400" : "text-gray-600" } text-sm`} > - {t("auth:password-validate-case")} + {t("form-password:validate-case")}
@@ -464,7 +463,7 @@ export default function SignUp() { passwordErrorNumber ? "text-gray-400" : "text-gray-600" } text-sm`} > - {t("auth:password-validate-number")} + {t("form-password:validate-number")}
@@ -531,14 +530,11 @@ export default function SignUp() { return (
- {t("auth:meta.signup.title")} + {t("common:head-title", { title: t("signup:title") })} - - + +
diff --git a/frontend/pages/users/[id].js b/frontend/pages/users/[id].js index 1ffc8e29f..46ebe6567 100644 --- a/frontend/pages/users/[id].js +++ b/frontend/pages/users/[id].js @@ -127,19 +127,21 @@ export default function Users() { return userList ? (
- {t("settings:meta.members.head-title")} + + {t("common:head-title", { title: t("settings-members:title") })} +

- {t("settings:meta.members.title")} + {t("settings-members:title")}

- {t("settings:meta.members.description")} + {t("settings-members:description")}

setSearchUsers(e.target.value)} - placeholder={t("settings:search-members")} + placeholder={t("section-members:search-members")} />