From 0e53b78708e0b1e82312c085a3a45a7e09e257e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=B4=EA=B0=95=EC=A4=80?= Date: Sun, 11 Dec 2022 10:54:53 +0900 Subject: [PATCH] feat(frontend): update translate library --- frontend/.vscode/settings.json | 2 +- frontend/components/basic/Layout.tsx | 57 ++--- .../basic/dialog/AddProjectMemberDialog.js | 2 +- frontend/components/dashboard/DropZone.tsx | 2 +- .../components/navigation/NavBarDashboard.tsx | 11 +- .../utilities/withTranslateProps.ts | 52 +++++ frontend/const.js | 5 + frontend/i18n.js | 27 --- frontend/locales/en-US.json | 216 ------------------ frontend/locales/ko-KR.json | 216 ------------------ frontend/next-i18next.config.js | 13 +- frontend/next.config.js | 1 - frontend/pages/_app.js | 14 +- frontend/pages/dashboard/[id].js | 5 +- frontend/pages/integrations/[id].js | 7 +- frontend/pages/login.js | 20 +- frontend/pages/settings/billing/[id].js | 8 +- frontend/pages/settings/org/[id].js | 10 +- frontend/pages/settings/personal/[id].js | 35 +-- frontend/pages/settings/project/[id].js | 9 +- frontend/pages/signup.tsx | 43 ++-- frontend/pages/users/[id].js | 10 +- frontend/public/locales/en/billing.json | 28 +++ frontend/public/locales/en/common.json | 26 +++ frontend/public/locales/en/dashboard.json | 19 ++ frontend/public/locales/en/integrations.json | 9 + frontend/public/locales/en/login.json | 8 + frontend/public/locales/en/nav.json | 22 ++ .../public/locales/en/section-incident.json | 11 + .../public/locales/en/section-members.json | 14 ++ .../public/locales/en/section-password.json | 11 + frontend/public/locales/en/section-token.json | 13 ++ .../public/locales/en/settings-members.json | 4 + frontend/public/locales/en/settings-org.json | 4 + .../public/locales/en/settings-personal.json | 11 + .../public/locales/en/settings-project.json | 13 ++ frontend/public/locales/en/signup.json | 21 ++ frontend/public/locales/ko/billing.json | 28 +++ frontend/public/locales/ko/common.json | 26 +++ frontend/public/locales/ko/dashboard.json | 19 ++ frontend/public/locales/ko/integrations.json | 9 + frontend/public/locales/ko/login.json | 8 + frontend/public/locales/ko/nav.json | 22 ++ .../public/locales/ko/section-incident.json | 11 + .../public/locales/ko/section-members.json | 14 ++ .../public/locales/ko/section-password.json | 11 + frontend/public/locales/ko/section-token.json | 13 ++ .../public/locales/ko/settings-members.json | 4 + frontend/public/locales/ko/settings-org.json | 4 + .../public/locales/ko/settings-personal.json | 11 + .../public/locales/ko/settings-project.json | 13 ++ frontend/public/locales/ko/signup.json | 21 ++ frontend/tsconfig.json | 2 +- 53 files changed, 645 insertions(+), 550 deletions(-) create mode 100644 frontend/components/utilities/withTranslateProps.ts delete mode 100644 frontend/i18n.js delete mode 100644 frontend/locales/en-US.json delete mode 100644 frontend/locales/ko-KR.json create mode 100644 frontend/public/locales/en/billing.json create mode 100644 frontend/public/locales/en/common.json create mode 100644 frontend/public/locales/en/dashboard.json create mode 100644 frontend/public/locales/en/integrations.json create mode 100644 frontend/public/locales/en/login.json create mode 100644 frontend/public/locales/en/nav.json create mode 100644 frontend/public/locales/en/section-incident.json create mode 100644 frontend/public/locales/en/section-members.json create mode 100644 frontend/public/locales/en/section-password.json create mode 100644 frontend/public/locales/en/section-token.json create mode 100644 frontend/public/locales/en/settings-members.json create mode 100644 frontend/public/locales/en/settings-org.json create mode 100644 frontend/public/locales/en/settings-personal.json create mode 100644 frontend/public/locales/en/settings-project.json create mode 100644 frontend/public/locales/en/signup.json create mode 100644 frontend/public/locales/ko/billing.json create mode 100644 frontend/public/locales/ko/common.json create mode 100644 frontend/public/locales/ko/dashboard.json create mode 100644 frontend/public/locales/ko/integrations.json create mode 100644 frontend/public/locales/ko/login.json create mode 100644 frontend/public/locales/ko/nav.json create mode 100644 frontend/public/locales/ko/section-incident.json create mode 100644 frontend/public/locales/ko/section-members.json create mode 100644 frontend/public/locales/ko/section-password.json create mode 100644 frontend/public/locales/ko/section-token.json create mode 100644 frontend/public/locales/ko/settings-members.json create mode 100644 frontend/public/locales/ko/settings-org.json create mode 100644 frontend/public/locales/ko/settings-personal.json create mode 100644 frontend/public/locales/ko/settings-project.json create mode 100644 frontend/public/locales/ko/signup.json diff --git a/frontend/.vscode/settings.json b/frontend/.vscode/settings.json index 1a6546263e..b2ae7a5ea3 100644 --- a/frontend/.vscode/settings.json +++ b/frontend/.vscode/settings.json @@ -3,5 +3,5 @@ "locales", "public/locales" ], - "i18n-ally.sourceLanguage": "en-US" + "i18n-ally.sourceLanguage": "en" } \ No newline at end of file diff --git a/frontend/components/basic/Layout.tsx b/frontend/components/basic/Layout.tsx index 6edb7ede5d..ad15e072ce 100644 --- a/frontend/components/basic/Layout.tsx +++ b/frontend/components/basic/Layout.tsx @@ -1,9 +1,9 @@ /* eslint-disable no-unexpected-multiline */ /* eslint-disable react-hooks/exhaustive-deps */ -import { useEffect, useState } from "react"; +import { useEffect, useMemo, useState } from "react"; import Link from "next/link"; import { useRouter } from "next/router"; -import useTranslation from "next-translate/useTranslation"; +import { useTranslation } from "next-i18next"; import { faBookOpen, faGear, @@ -130,31 +130,34 @@ export default function Layout({ children }: LayoutProps) { } } - const menuItems = [ - { - href: - "/dashboard/" + - workspaceMapping[workspaceSelected as any] + - "?Development", - title: t("nav:menu.secrets"), - emoji: , - }, - { - href: "/users/" + workspaceMapping[workspaceSelected as any], - title: t("nav:menu.members"), - emoji: , - }, - { - href: "/integrations/" + workspaceMapping[workspaceSelected as any], - title: t("nav:menu.integrations"), - emoji: , - }, - { - href: "/settings/project/" + workspaceMapping[workspaceSelected as any], - title: t("nav:menu.project-settings"), - emoji: , - }, - ]; + const menuItems = useMemo( + () => [ + { + href: + "/dashboard/" + + workspaceMapping[workspaceSelected as any] + + "?Development", + title: t("nav:menu.secrets"), + emoji: , + }, + { + href: "/users/" + workspaceMapping[workspaceSelected as any], + title: t("nav:menu.members"), + emoji: , + }, + { + href: "/integrations/" + workspaceMapping[workspaceSelected as any], + title: t("nav:menu.integrations"), + emoji: , + }, + { + href: "/settings/project/" + workspaceMapping[workspaceSelected as any], + title: t("nav:menu.project-settings"), + emoji: , + }, + ], + [t] + ); useEffect(() => { // Put a user in a workspace if they're not in one yet diff --git a/frontend/components/basic/dialog/AddProjectMemberDialog.js b/frontend/components/basic/dialog/AddProjectMemberDialog.js index be875d65c4..13e39baff5 100644 --- a/frontend/components/basic/dialog/AddProjectMemberDialog.js +++ b/frontend/components/basic/dialog/AddProjectMemberDialog.js @@ -1,7 +1,7 @@ import { Fragment, useState } from "react"; import { useRouter } from "next/router"; import Trans from "next-translate/Trans"; -import useTranslation from "next-translate/useTranslation"; +import { useTranslation } from "next-i18next"; import { Dialog, Transition } from "@headlessui/react"; import Button from "../buttons/Button"; diff --git a/frontend/components/dashboard/DropZone.tsx b/frontend/components/dashboard/DropZone.tsx index 4bc684cea6..81e5792f24 100644 --- a/frontend/components/dashboard/DropZone.tsx +++ b/frontend/components/dashboard/DropZone.tsx @@ -1,6 +1,6 @@ import { type ChangeEvent, type DragEvent, useState } from "react"; import Image from "next/image"; -import useTranslation from "next-translate/useTranslation"; +import { useTranslation } from "next-i18next"; import { faUpload } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; diff --git a/frontend/components/navigation/NavBarDashboard.tsx b/frontend/components/navigation/NavBarDashboard.tsx index 159a69daa4..6712eb30a0 100644 --- a/frontend/components/navigation/NavBarDashboard.tsx +++ b/frontend/components/navigation/NavBarDashboard.tsx @@ -2,7 +2,7 @@ import React, { Fragment, useEffect, useMemo, useState } from "react"; import Image from "next/image"; import { useRouter } from "next/router"; -import useTranslation from "next-translate/useTranslation"; +import { TFunction, useTranslation } from "next-i18next"; import { faGithub, faSlack } from "@fortawesome/free-brands-svg-icons"; import { faCircleQuestion } from "@fortawesome/free-regular-svg-icons"; import { @@ -17,15 +17,16 @@ import { import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { Menu, Transition } from "@headlessui/react"; +import logout from "~/pages/api/auth/Logout"; + import getOrganization from "../../pages/api/organization/GetOrg"; import getOrganizations from "../../pages/api/organization/getOrgs"; import getUser from "../../pages/api/user/getUser"; import guidGenerator from "../utilities/randomId"; -import logout from "~/pages/api/auth/Logout"; /** * @param {(key: string) => string} t */ -const supportOptions = (t) => [ +const supportOptions = (t: TFunction) => [ [ , t("nav:support.slack"), @@ -69,7 +70,7 @@ export default function Navbar() { const [orgs, setOrgs] = useState([]); const [currentOrg, setCurrentOrg] = useState(); - const { t } = useTranslation(""); + const { t } = useTranslation(); const supportOptionsList = useMemo(() => supportOptions(t), [t]); @@ -128,7 +129,7 @@ export default function Navbar() { diff --git a/frontend/components/utilities/withTranslateProps.ts b/frontend/components/utilities/withTranslateProps.ts new file mode 100644 index 0000000000..6dc9abd108 --- /dev/null +++ b/frontend/components/utilities/withTranslateProps.ts @@ -0,0 +1,52 @@ +import { GetServerSideProps, GetStaticProps } from "next"; +import { serverSideTranslations } from "next-i18next/serverSideTranslations"; + +const DefaultNamespaces = ["common", "nav"]; + +type GetTranslatedStaticProps = ( + namespaces: string[], + getStaticProps?: GetStaticProps +) => GetStaticProps; + +type GetTranslatedServerSideProps = ( + namespaces: string[], + getStaticProps?: GetServerSideProps +) => GetServerSideProps; + +export const getTranslatedStaticProps: GetTranslatedStaticProps = + (namespaces, getStaticProps) => + async ({ locale, ...context }) => { + let staticProps = { props: {} }; + if (typeof getStaticProps === "function") { + staticProps = (await getStaticProps(context)) as any; + } + return { + ...staticProps, + props: { + ...(await serverSideTranslations(locale ?? "en", [ + ...DefaultNamespaces, + ...namespaces, + ])), + ...staticProps.props, + }, + }; + }; + +export const getTranslatedServerSideProps: GetTranslatedServerSideProps = + (namespaces, getServerSideProps) => + async ({ locale, ...context }) => { + let staticProps = { props: {} }; + if (typeof getServerSideProps === "function") { + staticProps = (await getServerSideProps(context)) as any; + } + return { + ...staticProps, + props: { + ...(await serverSideTranslations(locale ?? "en", [ + ...DefaultNamespaces, + ...namespaces, + ])), + ...staticProps.props, + }, + }; + }; diff --git a/frontend/const.js b/frontend/const.js index f3b285e438..195d54a6de 100644 --- a/frontend/const.js +++ b/frontend/const.js @@ -16,3 +16,8 @@ export const publicPaths = [ `/terms`, `/subprocessors`, ]; + +export const languageMap = { + en: "English", + ko: "한국어", +}; diff --git a/frontend/i18n.js b/frontend/i18n.js deleted file mode 100644 index cb65ce2198..0000000000 --- a/frontend/i18n.js +++ /dev/null @@ -1,27 +0,0 @@ -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] ?? {} )"; - -module.exports = { - 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", "form-password"], - "/settings/billing/[id]": ["billing"], - "/integrations/[id]": ["integrations"], - }, -}; diff --git a/frontend/locales/en-US.json b/frontend/locales/en-US.json deleted file mode 100644 index defb49856b..0000000000 --- a/frontend/locales/en-US.json +++ /dev/null @@ -1,216 +0,0 @@ -{ - "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", - "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", - "environment": "Environment", - "expired-in": "Expires in", - "language": "Language", - "search": "Search..." - }, - "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": { - "slack": "[NEW] Join Slack Forum", - "docs": "Read Docs", - "issue": "Open a Github Issue", - "email": "Send us an Email" - }, - "user": { - "signed-in-as": "SIGNED IN AS", - "current-organization": "CURRENT ORGANIZATION", - "usage-billing": "Usage & Billing", - "invite": "Invite Members", - "other-organizations": "OTHER ORGANIZATION" - }, - "menu": { - "project": "PROJECT", - "secrets": "Secrets", - "members": "Members", - "integrations": "Integrations", - "project-settings": "Project Settings" - } - }, - "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", - "need-account": "Need an Infisical 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", - "step2-message": "We've sent a verification email to{{email}}", - "step2-code-error": "Oops. Your code is wrong. Please try again.", - "step2-spam-alert": "Make sure to check your spam inbox.", - "step3-message": "Almost there!", - "step4-message": "Save your Emergency Kit", - "step4-description1": "If you get locked out of your account, your Emergency Kit is the only way to sign in.", - "step4-description2": "We recommend you download it and keep it somewhere safe.", - "step4-description3": "It contains your Secret Key which we cannot access or recover for you if you lose it.", - "step4-download": "Download PDF" - }, - "dashboard": { - "title": "Secrets", - "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": "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" - }, - "change-language": "Change Language" - }, - "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" - } - }, - "billing": { - "title": "Usage & Billing", - "description": "View and manage your organization's subscription here", - "subscription": "Subscription", - "starter": { - "name": "Starter", - "price-explanation": "up to 5 team members", - "text": "Manage any project with 5 members for free!", - "subtext": "$5 per member/month afterwards." - }, - "professional": { - "name": "Professional", - "price-explanation": "/member/month", - "subtext": "Includes unlimited projects & members.", - "text": "Keep up with key management as you grow." - }, - "enterprise": { - "name": "Enterprise", - "text": "Keep up with key management as you grow." - }, - "current-usage": "Current Usage", - "free": "Free", - "downgrade": "Downgrade", - "upgrade": "Upgrade", - "learn-more": "Learn More", - "custom-pricing": "Custom Pricing", - "schedule-demo": "Schedule a Demo" - }, - "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.", - "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" - } - }, - "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": "Platform & Cloud 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 deleted file mode 100644 index e76d688255..0000000000 --- a/frontend/locales/ko-KR.json +++ /dev/null @@ -1,216 +0,0 @@ -{ - "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": "메일", - "password": "비밀번호", - "first-name": "이름", - "last-name": "성", - "logout": "로그아웃", - "validate-required": "{{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": "클릭하여 복사하기", - "project-id": "프로젝트 ID", - "save-changes": "변경사항 저장하기", - "saved": "저장됨", - "drop-zone": ".env 파일을 이곳에 드래그 & 드롭 하세요.", - "drop-zone-keys": "이곳에 .env 파일을 드래그 & 드롭 하여 더 많은 키들을 추가하세요.", - "role": "Role", - "role_admin": "admin", - "display-name": "표시 이름", - - "environment": "환경", - "expired-in": "만료 기한:", - "language": "언어", - "search": "검색하기..." - }, - "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": "한줄의 코드르 .env파일을 교체하세요. 3분이면 가입할 수 있어요.", - "og-description": "Infisical은 팀원과 .env파일을 공유하고 연동할 수 있는 심플한 end-to-end 암호화 플렛폼입니다. Node.js, Next.js, Gatsby, Nest.js 와 같은 다양한 플렛폼에서 작동해요.", - "signup": "회원가입", - "already-have-account": "이미 계정이 있나요? 로그인하기", - "forgot-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": { - "title": "시크릿", - "og-title": "빠르게 .env 파일을 관리하세요", - "og-description": "Infisical은 팀원과 .env파일을 공유할 수 있는 심플한 end-to-end 암호화 플렛폼입니다.", - "search-keys": "키 검색하기...", - "add-key": "키 추가하기", - "personal": "개인", - "personal-description": "개인 키는 오직 본인만 볼 수 있어요", - "shared": "공유", - "shared-description": "공유 키는 팀 전체가 볼 수 있어요", - "make-shared": "공유로 만들기", - "make-personal": "개인으로 만들기", - "check-docs": { - "button": "문서 확인하기", - "title": "좋았어요!", - "line1": "더 많은 시크릿들을 추가한 것을 축하합니다.", - "line2": "코드와 연결하는 사용하는 방법을 한번 알아보지 않을래요?" - } - }, - "settings-members": { - "title": "맴버 설정", - "description": "선택한 프로젝트의 맴버를 확인하세요." - }, - "settings-org": { - "title": "조직 설정", - "description": "조직의 맴버를 관리하세요." - }, - "settings-personal": { - "title": "개인 설정", - "description": "계정 및 기본적인 설정을 확인하고 변경하세요.", - "emergency": { - "name": "긴급복구 키트", - "text1": "긴급복구 키트는 Infisical계정에 로그인 할 수 있는 정보를 가지고 있어요.", - "text2": "오직 마지막으로 발급한 긴급복구 키트만 사용 가능해요. 새로운 긴급복구 키트를 받으려면, 비밀번호를 입력하세요.", - "download": "긴급복구 키트 다운로드" - }, - "change-language": "언어 변경하기" - }, - "settings-project": { - "title": "프로젝트 설정", - "description": "현재 선택한 프로젝트에 대해서 설정해요.", - "auto-generated": "자동으로 생성된 고유한 키 입니다. 변경할 수 없어요.", - "danger-zone": "위험존", - "danger-zone-note": "프로젝트를 삭제한다면 모든 키가 즉시 삭제되며 다시는 되돌릴 수 없어요. 삭제를 원한다면 프로젝트 이름을 아래에 적어주세요.", - "delete-project": "프로젝트 삭제", - "delete-project-note": "노트: 최소 한개 이상의 프로젝트는 조직에 존재해야 해요.", - "docs": "Infisical 문서", - "project-id-description": "다른 코드에서 Infisical과 환경변수를 연동하기 위해서는 프로젝트 ID가 필요해요.", - "project-id-description2": "다양한 언어 및 프레임워크에 대한 가이드를 확인하고 싶다면, 다음을 확인하세요. ", - "project-to-delete": "삭제할 프로젝트" - }, - "billing": { - "title": "요금제 & 결제", - "description": "이곳에서 조직의 구독을 확인하고 관리할 수 있어요.", - "subscription": "구독", - "starter": { - "name": "스타터", - "price-explanation": "5명의 팀 맴버까지", - "text": "어떤 프로젝트든 다섯명의 맴버까지 무료로 이용할 수 있어요!", - "subtext": "$5명/달 로 바뀔 예정입니다." - }, - "professional": { - "name": "전문가", - "price-explanation": "/맴버/달", - "subtext": "무제한의 프로젝트와 맴버", - "text": "조직의 성장에 따라 유연하게 시크릿을 관리하세요." - }, - "enterprise": { - "name": "엔터프라이즈", - "text": "조직의 성장에 따라 유연하게 시크릿을 관리하세요." - }, - "current-usage": "현재 요금제", - "free": "무료", - "downgrade": "다운그레이드", - "upgrade": "업그레이드", - "learn-more": "자세히 알아보기", - "custom-pricing": "커스텀 가격", - "schedule-demo": "데모 예약하기" - }, - "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": "조직에 유저 추가하기" - }, - "org-members-description": "조직의 맴버들을 관리하세요." - }, - "integrations": { - "available": "사용 가능한 연동", - "available-text1": "연결하고 싶은 서비스를 클릭하세요. 환경 변수가 선택한 외부 서비스와 자동으로 연동됩니다.", - "available-text2": "참고: Heroku와의 연동에서는 보안상의 이유로 End-To-End 암호화를 유지하는 것이 불가능합니다. 이론적으로는 Infisical이 시크릿을 읽는것이 가능하지만, 절대 그러지 않는다고 확신할 수 있습니다. 핵심 Infisical 서비스는 항상 End-To-End 암호화 상태를 유지합니다. 질문이 있으면 support@infisical.com으로 문의하세요.", - "description": "외부 서비스와 함께 Infisical을 연동하고 관리하세요", - "no-integrations1": "연동된 서비스가 없어요. 연동하게 된다면 이곳에서 표시돼요.", - "no-integrations2": "시작하려면, 아래의 옵션을 클릭하세요. 대체로 5분 이내로 가능해요.", - "title": "프로젝트 연동" - }, - "section-incident": { - "add-contact": "연락처 추가하기", - "add-dialog": { - "add-incident": "비상 연락처 추가하기", - "description": "중대한 일이 생길 경우, 이 연락처로 알림이 전송됩니다.", - "title": "비상 연락처 추가하기" - }, - "incident-contacts": "비상 연락망", - "incident-contacts-description": "중대한 일이 생길 경우, 아래의 연락처로 알림이 전송됩니다.", - "no-incident-contacts": "비상 연락망이 존재하지 않아요." - }, - "section-token": { - "add-dialog": { - "add": "서비스 토큰 추가하기", - "copy-service-token": "서비스 토큰 복사하기", - "copy-service-token-description": "팝업을 닫을 시 다시는 토큰을 확인할 수 없어요.", - "description": "이름, 환경, 만료일을 지정하세요. 토큰이 생성되면 최초 한번만 볼 수 있어요. 안전한 곳에 저장하세요.", - "name": "서비스 토큰 이름", - "title": "{{target}}의 토큰 추가하기" - }, - "add-new": "새 토큰 추가하기", - "service-tokens": "서비스 토큰", - "service-tokens-description": "모든 서비스 토큰은 프로젝트 및 환경에 따라 다릅니다." - } -} diff --git a/frontend/next-i18next.config.js b/frontend/next-i18next.config.js index d6812e5b3f..698cf62b1f 100644 --- a/frontend/next-i18next.config.js +++ b/frontend/next-i18next.config.js @@ -8,18 +8,7 @@ module.exports = { debug: process.env.NODE_ENV === "development", i18n: { defaultLocale: "en", - locales: ["en", "de"], - }, - /** To avoid issues when deploying to some paas (vercel...) */ - // localePath: - // typeof window === "undefined" - // ? require("path").resolve("./public/locales") - // : "/locales", - localePath: (locale, namespace, missing) => { - const data = JSON.parse( - require("path").resolve(`./public/locales/${locale}.json`) - ); - return data.default[namespace]; + locales: ["en", "ko"], }, reloadOnPrerender: process.env.NODE_ENV === "development", diff --git a/frontend/next.config.js b/frontend/next.config.js index cb44c4ac55..0b87ee4c76 100644 --- a/frontend/next.config.js +++ b/frontend/next.config.js @@ -1,5 +1,4 @@ const { i18n } = require("./next-i18next.config.js"); -const nextTranslate = require("next-translate"); const ContentSecurityPolicy = ` default-src 'self'; diff --git a/frontend/pages/_app.js b/frontend/pages/_app.js index 907bbc9413..56d030da12 100644 --- a/frontend/pages/_app.js +++ b/frontend/pages/_app.js @@ -1,5 +1,6 @@ import { useEffect } from "react"; import { useRouter } from "next/router"; +import { appWithTranslation } from "next-i18next"; import { config } from "@fortawesome/fontawesome-svg-core"; import { initPostHog } from "~/components/analytics/posthog"; @@ -18,6 +19,17 @@ const App = ({ Component, pageProps, ...appProps }) => { const router = useRouter(); const posthog = initPostHog(); + // useEffect(() => { + // const storedLang = localStorage.getItem("lang"); + // console.log(router.locale); + // console.log(storedLang); + // if (router.locale ?? "en" !== storedLang ?? "en") { + // router.push(router.pathname, router.pathname, { + // locale: storedLang ?? "en", + // }); + // } + // }, [router.locale, router.pathname]); + useEffect(() => { // Init for auto capturing const posthog = initPostHog(); @@ -56,7 +68,7 @@ const App = ({ Component, pageProps, ...appProps }) => { ); }; -export default App; +export default appWithTranslation(App); { /*