From d889c3b144eac05ed530eae86de327ebfa57b445 Mon Sep 17 00:00:00 2001 From: Antoine Jaussoin Date: Sun, 8 May 2022 20:13:33 +0100 Subject: [PATCH] Internationalisation, i18next, translating all languages (#403) * add i18next * welcome * typescript * converted files * Convert all translations to i18next * Fix previous game * French * Remove some translations * Remove previous translations * Re-instate language provider * crowdin config * Crowdin config * Original languages before translations * Downloading MT translations * Chinese taditional * Arabic * Fix language loading * Setting language * Setting language * Rename all files to make plurals work * Rename all files to make plurals work * Missing translations * Migrate default langues * clean up * Linting * readme, fixes, integration tests * remove uncessary local storage * integration * fixes * fixes * Making language nullable * trying to remove vuln --- .github/workflows/alpha.yml | 2 +- README.md | 1 + backend/.gitignore | 3 +- backend/src/auth/passport.ts | 6 - backend/src/common/types.ts | 2 +- backend/src/db/actions/users.ts | 24 +- backend/src/db/entities/User.ts | 6 +- backend/src/db/entities/UserView.ts | 4 +- .../1652023488716-MigrateLanguages.ts | 39 ++ .../1652028782451-DefaultLanguage.ts | 14 + .../migrations/1652033290129-NullLanguage.ts | 16 + crowdin.yml | 11 + dependencies.md | 1 - docs/docs/self-hosting/optionals.md | 2 +- frontend/Dockerfile | 5 +- frontend/docker/frontend-entrypoint.sh | 2 +- frontend/package.json | 4 + frontend/src/App.tsx | 80 +-- frontend/src/auth/AccountMenu.tsx | 12 +- frontend/src/auth/modal/AnonAuth.tsx | 24 +- frontend/src/auth/modal/LoginModal.tsx | 10 +- frontend/src/auth/modal/SocialAuth.tsx | 18 +- frontend/src/auth/modal/account/Login.tsx | 27 +- .../src/auth/modal/account/LostPassword.tsx | 17 +- frontend/src/auth/modal/account/Register.tsx | 48 +- frontend/src/components/LanguagePicker.tsx | 6 +- frontend/src/components/ProButton/index.tsx | 40 +- frontend/src/hooks/useFormatDate.ts | 2 +- frontend/src/index.tsx | 1 + frontend/src/state/columns.ts | 43 +- frontend/src/state/templates.ts | 24 +- frontend/src/state/types.ts | 3 + frontend/src/testing/index.tsx | 4 +- frontend/src/translations/Context.tsx | 9 - .../src/translations/LanguageProvider.tsx | 49 +- frontend/src/translations/ar.ts | 403 --------------- frontend/src/translations/de.ts | 410 --------------- frontend/src/translations/en.ts | 485 ------------------ frontend/src/translations/es.ts | 406 --------------- frontend/src/translations/fr.ts | 481 ----------------- frontend/src/translations/hu.ts | 406 --------------- frontend/src/translations/i18n.ts | 32 ++ frontend/src/translations/index.ts | 5 - frontend/src/translations/it.ts | 416 --------------- frontend/src/translations/ja.ts | 404 --------------- frontend/src/translations/languages.ts | 78 +-- frontend/src/translations/locales/ar-SA.json | 423 +++++++++++++++ frontend/src/translations/locales/de-DE.json | 423 +++++++++++++++ frontend/src/translations/locales/en-GB.json | 423 +++++++++++++++ frontend/src/translations/locales/es-ES.json | 423 +++++++++++++++ frontend/src/translations/locales/fr-FR.json | 423 +++++++++++++++ frontend/src/translations/locales/hu-HU.json | 423 +++++++++++++++ frontend/src/translations/locales/it-IT.json | 423 +++++++++++++++ frontend/src/translations/locales/ja-JP.json | 423 +++++++++++++++ frontend/src/translations/locales/nl-NL.json | 423 +++++++++++++++ frontend/src/translations/locales/pl-PL.json | 423 +++++++++++++++ frontend/src/translations/locales/pt-BR.json | 423 +++++++++++++++ frontend/src/translations/locales/pt-PT.json | 423 +++++++++++++++ frontend/src/translations/locales/ru-RU.json | 403 +++++++++++++++ frontend/src/translations/locales/uk-UA.json | 423 +++++++++++++++ frontend/src/translations/locales/zh-CN.json | 423 +++++++++++++++ frontend/src/translations/locales/zh-TW.json | 423 +++++++++++++++ frontend/src/translations/nl.ts | 416 --------------- frontend/src/translations/pl.ts | 406 --------------- frontend/src/translations/pt-br.ts | 406 --------------- frontend/src/translations/react-i18next.d.ts | 11 + frontend/src/translations/readme.md | 23 + frontend/src/translations/ru.ts | 404 --------------- frontend/src/translations/types.ts | 408 --------------- frontend/src/translations/useLanguage.ts | 42 +- frontend/src/translations/useTranslations.ts | 71 --- frontend/src/translations/utils.ts | 10 - frontend/src/translations/zh-cn.ts | 404 --------------- frontend/src/translations/zh-tw.ts | 404 --------------- frontend/src/utils/getConfig.ts | 11 +- frontend/src/views/Game.tsx | 23 +- frontend/src/views/Home.tsx | 12 +- frontend/src/views/Panel.tsx | 20 +- frontend/src/views/Reset.tsx | 23 +- frontend/src/views/Validate.tsx | 12 +- frontend/src/views/account/AccountPage.tsx | 51 +- frontend/src/views/account/MembersEditor.tsx | 14 +- .../src/views/account/delete/DeleteModal.tsx | 66 ++- frontend/src/views/admin/NewAccountModal.tsx | 27 +- frontend/src/views/game/GameFooter.tsx | 8 +- frontend/src/views/game/Unauthorized.tsx | 12 +- frontend/src/views/game/board/Column.tsx | 6 +- frontend/src/views/game/board/Group.tsx | 8 +- .../views/game/board/header/BoardHeader.tsx | 30 +- .../game/board/header/EncryptionModal.tsx | 8 +- .../views/game/board/header/LockSession.tsx | 20 +- .../views/game/board/header/ModifyOptions.tsx | 6 +- .../game/board/header/RemainingVotes.tsx | 31 +- .../views/game/board/header/RevealButton.tsx | 16 +- frontend/src/views/game/board/post/Post.tsx | 26 +- frontend/src/views/game/chat/Chat.tsx | 6 +- frontend/src/views/game/summary/SpeedDial.tsx | 16 +- .../src/views/game/summary/SummaryMode.tsx | 13 +- .../src/views/game/summary/useMarkdown.ts | 8 +- frontend/src/views/game/useColumns.ts | 8 +- frontend/src/views/game/useGame.ts | 22 +- frontend/src/views/home/CreateSession.tsx | 8 +- frontend/src/views/home/TrialPrompt.tsx | 32 +- .../views/home/game-item/EncryptedLock.tsx | 12 +- .../views/home/game-item/PreviousGameItem.tsx | 49 +- .../home/game-item/PrivateSessionIcon.tsx | 10 +- frontend/src/views/layout/Invite.tsx | 14 +- frontend/src/views/panel/ParticipantsList.tsx | 6 +- .../views/session-editor/SessionEditor.tsx | 34 +- .../sections/posts/PostsSection.tsx | 42 +- .../sections/template/TemplateEditor.tsx | 42 +- .../sections/template/TemplatePicker.tsx | 6 +- .../sections/template/TemplateSection.tsx | 17 +- .../sections/votes/VotingSection.tsx | 25 +- .../src/views/subscribe/SubscribePage.tsx | 44 +- .../views/subscribe/components/Product.tsx | 17 +- frontend/yarn.lock | 53 +- integration/cypress/integration/test.spec.js | 2 +- k8s/frontend-deployment.yaml | 2 +- self-hosting/docker-compose.full.yml | 2 +- 120 files changed, 7696 insertions(+), 7062 deletions(-) create mode 100644 backend/src/db/migrations/1652023488716-MigrateLanguages.ts create mode 100644 backend/src/db/migrations/1652028782451-DefaultLanguage.ts create mode 100644 backend/src/db/migrations/1652033290129-NullLanguage.ts create mode 100644 crowdin.yml delete mode 100644 frontend/src/translations/Context.tsx delete mode 100644 frontend/src/translations/ar.ts delete mode 100644 frontend/src/translations/de.ts delete mode 100644 frontend/src/translations/en.ts delete mode 100644 frontend/src/translations/es.ts delete mode 100644 frontend/src/translations/fr.ts delete mode 100644 frontend/src/translations/hu.ts create mode 100644 frontend/src/translations/i18n.ts delete mode 100644 frontend/src/translations/it.ts delete mode 100644 frontend/src/translations/ja.ts create mode 100644 frontend/src/translations/locales/ar-SA.json create mode 100644 frontend/src/translations/locales/de-DE.json create mode 100644 frontend/src/translations/locales/en-GB.json create mode 100644 frontend/src/translations/locales/es-ES.json create mode 100644 frontend/src/translations/locales/fr-FR.json create mode 100644 frontend/src/translations/locales/hu-HU.json create mode 100644 frontend/src/translations/locales/it-IT.json create mode 100644 frontend/src/translations/locales/ja-JP.json create mode 100644 frontend/src/translations/locales/nl-NL.json create mode 100644 frontend/src/translations/locales/pl-PL.json create mode 100644 frontend/src/translations/locales/pt-BR.json create mode 100644 frontend/src/translations/locales/pt-PT.json create mode 100644 frontend/src/translations/locales/ru-RU.json create mode 100644 frontend/src/translations/locales/uk-UA.json create mode 100644 frontend/src/translations/locales/zh-CN.json create mode 100644 frontend/src/translations/locales/zh-TW.json delete mode 100644 frontend/src/translations/nl.ts delete mode 100644 frontend/src/translations/pl.ts delete mode 100644 frontend/src/translations/pt-br.ts create mode 100644 frontend/src/translations/react-i18next.d.ts create mode 100644 frontend/src/translations/readme.md delete mode 100644 frontend/src/translations/ru.ts delete mode 100644 frontend/src/translations/types.ts delete mode 100644 frontend/src/translations/useTranslations.ts delete mode 100644 frontend/src/translations/utils.ts delete mode 100644 frontend/src/translations/zh-cn.ts delete mode 100644 frontend/src/translations/zh-tw.ts diff --git a/.github/workflows/alpha.yml b/.github/workflows/alpha.yml index 6da8cac20..41d36d2f4 100644 --- a/.github/workflows/alpha.yml +++ b/.github/workflows/alpha.yml @@ -2,7 +2,7 @@ name: 'Alpha Build' on: push: - branches: [v4160/docs] + branches: [v4160/i18n] jobs: build: diff --git a/README.md b/README.md index 8d7f1272a..d9ca40930 100644 --- a/README.md +++ b/README.md @@ -87,6 +87,7 @@ This will run a demo version, which you can turn into a fully licenced version b ### Version 4.16.0 +- Complete overhaul of the translations. Switching to [i18next](https://www.i18next.com). Translated all languages using Machine Learning (via Crowdin). - Fix the empty file download when logging using Google OAuth - Upgrade the documentation to the latest version of Docusaurus - Add more integration tests, covering password accounts and account deletion diff --git a/backend/.gitignore b/backend/.gitignore index 74e8720cf..7a8c044d2 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -1 +1,2 @@ -/ormconfig.json \ No newline at end of file +/ormconfig.json +/src/locales \ No newline at end of file diff --git a/backend/src/auth/passport.ts b/backend/src/auth/passport.ts index d79d69c3b..ed8457cc1 100644 --- a/backend/src/auth/passport.ts +++ b/backend/src/auth/passport.ts @@ -100,7 +100,6 @@ export default () => { return { name: profile.displayName, type: 'twitter', - language: 'en', photo: profile.photos?.length ? profile.photos[0].value : undefined, username: profile.username, email, @@ -124,7 +123,6 @@ export default () => { return { name: displayName, type: 'github', - language: 'en', photo: profile.photos?.length ? profile.photos[0].value : undefined, username: profile.username, email: email.value, @@ -141,7 +139,6 @@ export default () => { return { name: profile.displayName, type: 'google', - language: 'en', photo: profile.photos?.length ? profile.photos[0].value : undefined, username: email, email, @@ -156,7 +153,6 @@ export default () => { return { name: profile.displayName, type: 'slack', - language: 'en', photo: profile.user.image_192, username: email, email, @@ -172,7 +168,6 @@ export default () => { return { name: profile.displayName, type: 'microsoft', - language: 'en', username: email, email, }; @@ -184,7 +179,6 @@ export default () => { return { name: profile.fullName, type: 'okta', - language: 'en', username: email, email, }; diff --git a/backend/src/common/types.ts b/backend/src/common/types.ts index 6812799f3..a21cab1b8 100644 --- a/backend/src/common/types.ts +++ b/backend/src/common/types.ts @@ -130,7 +130,7 @@ export interface FullUser extends User { username: string | null; accountType: AccountType; photo: string | null; - language: string; + language: string | null; email: string | null; canDeleteSession: boolean; stripeId: string | null; diff --git a/backend/src/db/actions/users.ts b/backend/src/db/actions/users.ts index acf108058..e09745aa7 100644 --- a/backend/src/db/actions/users.ts +++ b/backend/src/db/actions/users.ts @@ -191,7 +191,7 @@ export async function registerUser( UserIdentityRepository ); - const identity = await getOrCreateIdentity( + const [identity, existing] = await getOrCreateIdentity( manager, registration.username, registration.email, @@ -211,7 +211,7 @@ export async function registerUser( user.photo = registration.photo || user.photo; user.email = registration.email; - if (registration.language) { + if (!existing && registration.language) { user.language = registration.language; } @@ -244,7 +244,6 @@ export async function registerAnonymousUser( const identity = new UserIdentityEntity(v4(), user, hashedPassword); identity.username = username; - user.language = 'en'; await userRepository.save(user); await identityRepository.save(identity); @@ -275,7 +274,7 @@ async function getOrCreateIdentity( username: string, email: string, accountType: AccountType -): Promise { +): Promise<[identity: UserIdentityEntity, existing: boolean]> { const identityRepository = manager.getCustomRepository( UserIdentityRepository ); @@ -287,33 +286,36 @@ async function getOrCreateIdentity( // In certain conditions, the user attached to the identity could be wrong if the user didn't have an email const identity = identities[0]; if (identity.user.email !== email) { - const user = await getOrCreateUser(manager, email); + const [user, existing] = await getOrCreateUser(manager, email); identity.user = user; + return [identity, existing]; } - return identity; + return [identity, true]; } - const user = await getOrCreateUser(manager, email); + const [user, existing] = await getOrCreateUser(manager, email); const identity = new UserIdentityEntity(v4(), user); - return identity; + return [identity, existing]; } async function getOrCreateUser( manager: EntityManager, email: string -): Promise { +): Promise<[identity: UserEntity, existing: boolean]> { const userRepository = manager.getCustomRepository(UserRepository); const existingUser = await userRepository.findOne({ where: { email }, }); if (existingUser) { - return existingUser; + return [existingUser, true]; } const user = new UserEntity(v4(), ''); user.email = email; - return await userRepository.saveAndReload(user); + const savedUser = await userRepository.saveAndReload(user); + + return [savedUser, false]; } async function updateUserPassword( diff --git a/backend/src/db/entities/User.ts b/backend/src/db/entities/User.ts index 3fcf3ee6f..2d69ed8ea 100644 --- a/backend/src/db/entities/User.ts +++ b/backend/src/db/entities/User.ts @@ -46,8 +46,8 @@ export default class UserEntity { public trial: Date | null; @Column({ nullable: false, default: 50 }) public quota: number; - @Column({ nullable: false, type: 'character varying', default: 'en' }) - public language: string; + @Column({ nullable: true, type: 'character varying' }) + public language: string | null; @ManyToOne(() => SessionTemplateEntity, { nullable: true, eager: false }) @Index() public defaultTemplate: SessionTemplateEntity | null | undefined; @@ -73,7 +73,7 @@ export default class UserEntity { this.id = id; this.name = name; this.email = null; - this.language = 'en'; + this.language = null; this.stripeId = null; this.currency = null; this.trial = null; diff --git a/backend/src/db/entities/UserView.ts b/backend/src/db/entities/UserView.ts index 3edf666c5..651d4bd71 100644 --- a/backend/src/db/entities/UserView.ts +++ b/backend/src/db/entities/UserView.ts @@ -50,7 +50,7 @@ export default class UserView { @ViewColumn() public photo: string | null; @ViewColumn() - public language: string; + public language: string | null; @ViewColumn() public ownSubscriptionsId: string | null; @ViewColumn() @@ -72,7 +72,7 @@ export default class UserView { this.id = id; this.identityId = identityId; this.name = name; - this.language = 'en'; + this.language = null; this.accountType = 'anonymous'; this.username = null; this.photo = null; diff --git a/backend/src/db/migrations/1652023488716-MigrateLanguages.ts b/backend/src/db/migrations/1652023488716-MigrateLanguages.ts new file mode 100644 index 000000000..4757dc819 --- /dev/null +++ b/backend/src/db/migrations/1652023488716-MigrateLanguages.ts @@ -0,0 +1,39 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +type Mapping = { from: string; to: string }; + +const mappings: Mapping[] = [ + { from: 'ar', to: 'ar-SA' }, + { from: 'de', to: 'de-DE' }, + { from: 'en', to: 'en-GB' }, + { from: 'es', to: 'es-ES' }, + { from: 'fr', to: 'fr-FR' }, + { from: 'hu', to: 'hu-HU' }, + { from: 'it', to: 'it-IT' }, + { from: 'ja', to: 'ja-JP' }, + { from: 'nl', to: 'nl-NL' }, + { from: 'pl', to: 'pl-PL' }, + { from: 'pt', to: 'pt-BR' }, + { from: 'ptbr', to: 'pt-PT' }, + { from: 'ru', to: 'uk-UA' }, + { from: 'zhcn', to: 'zh-CN' }, + { from: 'zhtw', to: 'zh-TW' }, +]; + +export class MigrateLanguages1652023488716 implements MigrationInterface { + public async up(queryRunner: QueryRunner): Promise { + for (const mapping of mappings) { + await queryRunner.query( + `UPDATE users SET language = '${mapping.to}' WHERE language = '${mapping.from}';` + ); + } + } + + public async down(queryRunner: QueryRunner): Promise { + for (const mapping of mappings) { + await queryRunner.query( + `UPDATE users SET language = '${mapping.from}' WHERE language = '${mapping.to}';` + ); + } + } +} diff --git a/backend/src/db/migrations/1652028782451-DefaultLanguage.ts b/backend/src/db/migrations/1652028782451-DefaultLanguage.ts new file mode 100644 index 000000000..e5204a064 --- /dev/null +++ b/backend/src/db/migrations/1652028782451-DefaultLanguage.ts @@ -0,0 +1,14 @@ +import {MigrationInterface, QueryRunner} from "typeorm"; + +export class DefaultLanguage1652028782451 implements MigrationInterface { + name = 'DefaultLanguage1652028782451' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "users" ALTER COLUMN "language" SET DEFAULT 'en-GB'`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "users" ALTER COLUMN "language" SET DEFAULT 'en'`); + } + +} diff --git a/backend/src/db/migrations/1652033290129-NullLanguage.ts b/backend/src/db/migrations/1652033290129-NullLanguage.ts new file mode 100644 index 000000000..0ae6b0f4b --- /dev/null +++ b/backend/src/db/migrations/1652033290129-NullLanguage.ts @@ -0,0 +1,16 @@ +import {MigrationInterface, QueryRunner} from "typeorm"; + +export class NullLanguage1652033290129 implements MigrationInterface { + name = 'NullLanguage1652033290129' + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "users" ALTER COLUMN "language" DROP NOT NULL`); + await queryRunner.query(`ALTER TABLE "users" ALTER COLUMN "language" DROP DEFAULT`); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "users" ALTER COLUMN "language" SET DEFAULT 'en-GB'`); + await queryRunner.query(`ALTER TABLE "users" ALTER COLUMN "language" SET NOT NULL`); + } + +} diff --git a/crowdin.yml b/crowdin.yml new file mode 100644 index 000000000..f0c66c4f4 --- /dev/null +++ b/crowdin.yml @@ -0,0 +1,11 @@ +"project_id" : "512896" +"base_path" : "." +"base_url" : "https://api.crowdin.com" +"preserve_hierarchy": true + +files: [ + { + "source" : "/frontend/src/translations/locales/en-GB.json", + "translation" : "/frontend/src/translations/locales/%locale%.json" + } +] \ No newline at end of file diff --git a/dependencies.md b/dependencies.md index a752f64e5..c44f446aa 100644 --- a/dependencies.md +++ b/dependencies.md @@ -9,4 +9,3 @@ - @types/node-fetch: 2.5.12 - redis 3.1.2 (new version incompatible with express-redis) - passport 0.5.0 (new version, including 0.5.2 breaks set user when using Docker, but not locally) - diff --git a/docs/docs/self-hosting/optionals.md b/docs/docs/self-hosting/optionals.md index 039ea2328..184343bdd 100644 --- a/docs/docs/self-hosting/optionals.md +++ b/docs/docs/self-hosting/optionals.md @@ -107,7 +107,7 @@ services: GA_ID: '' # Optional, Google Analytics ID (UA-1234456-7) SENTRY_URL: '' # Optional, Sentry URL (https://1234567890abcdef12345@sentry.io/1234567) GIPHY_API_KEY: '' # Optional, can be obtained here: https://developers.giphy.com/ - DEFAULT_LANGUAGE: 'en' # Set the default language for new users + DEFAULT_LANGUAGE: 'en-GB' # Set the default language for new users # -- Do Not Change -- BACKEND_HOST: backend # This should be the name of the backend service diff --git a/frontend/Dockerfile b/frontend/Dockerfile index ea258d8c6..577a4c1a9 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -25,7 +25,10 @@ COPY --chown=node:node ./.env ./.env RUN yarn build -FROM nginx:alpine +FROM nginx:latest + +RUN apt update +RUN apt -y remove libfreetype6 COPY --from=Node /home/node/app/build /usr/share/nginx/html COPY ./docker/nginx.conf.template /etc/nginx/conf.d/default.conf.template diff --git a/frontend/docker/frontend-entrypoint.sh b/frontend/docker/frontend-entrypoint.sh index ce852aa0e..889f50d47 100644 --- a/frontend/docker/frontend-entrypoint.sh +++ b/frontend/docker/frontend-entrypoint.sh @@ -10,6 +10,6 @@ sed -i "s#NO_GA#${GA_ID:-}#g" /usr/share/nginx/html/index.html sed -i "s#NO_SENTRY#${SENTRY_URL:-}#g" /usr/share/nginx/html/index.html sed -i "s#NO_GIPHY#${GIPHY_API_KEY:-}#g" /usr/share/nginx/html/index.html sed -i "s#NO_STRIPE#${STRIPE_KEY:-}#g" /usr/share/nginx/html/index.html -sed -i "s#NO_DEFAULT_LANGUAGE#${DEFAULT_LANGUAGE:-en}#g" /usr/share/nginx/html/index.html +sed -i "s#NO_DEFAULT_LANGUAGE#${DEFAULT_LANGUAGE:-en-GB}#g" /usr/share/nginx/html/index.html exec "$@" \ No newline at end of file diff --git a/frontend/package.json b/frontend/package.json index 0f5d48981..3153372a1 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -40,6 +40,9 @@ "emoji-mart": "3.0.1", "flag-icons": "6.2.0", "http-proxy-middleware": "2.0.6", + "i18next": "^21.6.16", + "i18next-browser-languagedetector": "^6.1.4", + "i18next-resources-to-backend": "^1.0.0", "isemail": "3.2.0", "lexorank": "1.0.4", "lodash": "4.17.21", @@ -57,6 +60,7 @@ "react-ga": "3.3.0", "react-giphy-searchbox": "1.5.4", "react-helmet": "6.1.0", + "react-i18next": "^11.16.7", "react-markdown": "8.0.3", "react-password-strength-bar": "0.4.0", "react-router-dom": "6.3.0", diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 83756c469..0dc313f91 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -18,45 +18,47 @@ import { ConfirmProvider } from 'material-ui-confirm'; function App() { return ( - - - - - - - - - - - - - - - - - }> - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + }> + + + + + + + + + + + + + ); } diff --git a/frontend/src/auth/AccountMenu.tsx b/frontend/src/auth/AccountMenu.tsx index a8cc5a807..4f4af5312 100644 --- a/frontend/src/auth/AccountMenu.tsx +++ b/frontend/src/auth/AccountMenu.tsx @@ -6,7 +6,6 @@ import Button from '@mui/material/Button'; import AccountIcon from '@mui/icons-material/AccountCircle'; import useUser from './useUser'; import LoginModal from './modal/LoginModal'; -import useTranslation from '../translations/useTranslations'; import { logout } from '../api'; import UserContext from './Context'; import Avatar from '../components/Avatar'; @@ -15,9 +14,10 @@ import { Key, Logout, Star } from '@mui/icons-material'; import { colors, Divider, ListItemIcon, ListItemText } from '@mui/material'; import AccountCircle from '@mui/icons-material/AccountCircle'; import useIsAdmin from './useIsAdmin'; +import { useTranslation } from 'react-i18next'; const AccountMenu = () => { - const translations = useTranslation(); + const { t } = useTranslation(); const { setUser } = useContext(UserContext); const [modalOpened, setModalOpen] = useState(false); const [menuOpen, setMenuOpen] = useState(false); @@ -98,7 +98,7 @@ const AccountMenu = () => { - {translations.Header.account} + {t('Header.account')} ) : null} {isAdmin ? ( @@ -106,7 +106,7 @@ const AccountMenu = () => { - {translations.Header.adminPanel} + {t('Header.adminPanel')} ) : null} {isAdmin || isNotAnon ? : null} @@ -114,7 +114,7 @@ const AccountMenu = () => { - {translations.Header.logout} + {t('Header.logout')} ) : null} @@ -130,7 +130,7 @@ const AccountMenu = () => { data-cy="login-button" startIcon={} > - {translations.AnonymousLogin.header} + {t('AnonymousLogin.header')} {modalOpened && } diff --git a/frontend/src/auth/modal/AnonAuth.tsx b/frontend/src/auth/modal/AnonAuth.tsx index 27f2a7fcf..1b5ddb90b 100644 --- a/frontend/src/auth/modal/AnonAuth.tsx +++ b/frontend/src/auth/modal/AnonAuth.tsx @@ -2,10 +2,11 @@ import { useCallback, useState } from 'react'; import Button from '@mui/material/Button'; import Input from '@mui/material/Input'; import { Alert } from '@mui/material'; -import useTranslations, { useLanguage } from '../../translations'; -import { anonymousLogin, updateLanguage } from '../../api'; +import { anonymousLogin, me, updateLanguage } from '../../api'; import { FullUser } from 'common'; import Wrapper from './Wrapper'; +import { useTranslation } from 'react-i18next'; +import { useLanguage } from 'translations'; interface AnonAuthProps { onClose: () => void; @@ -13,10 +14,10 @@ interface AnonAuthProps { } const AnonAuth = ({ onClose, onUser }: AnonAuthProps) => { - const { AnonymousLogin: loginTranslations } = useTranslations(); - const language = useLanguage(); + const { t } = useTranslation(); const [username, setUsername] = useState(''); const [error, setError] = useState(''); + const [language] = useLanguage(); const handleAnonLogin = useCallback(() => { async function login() { @@ -27,7 +28,10 @@ const AnonAuth = ({ onClose, onUser }: AnonAuthProps) => { setError('Your anonymous account is not valid.'); return; } - const updatedUser = await updateLanguage(language.value); + let updatedUser = await me(); + if (updatedUser?.language === null) { + updatedUser = await updateLanguage(language.locale); + } onUser(updatedUser); if (onClose) { onClose(); @@ -43,7 +47,7 @@ const AnonAuth = ({ onClose, onUser }: AnonAuthProps) => { return ( { disabled={!username.trim().length} data-cy="anon-login-button" > - {loginTranslations.buttonLabel} + {t('AnonymousLogin.buttonLabel')} } > - {loginTranslations.anonymousAuthDescription} + {t('AnonymousLogin.anonymousAuthDescription')} {!!error ? ( @@ -67,8 +71,8 @@ const AnonAuth = ({ onClose, onUser }: AnonAuthProps) => { { const hasNoSocialMediaAuth = !any; const hasNoWayOfLoggingIn = hasNoSocialMediaAuth && disableAnonymous && disablePasswords; - const translations = useTranslations(); + const { t } = useTranslation(); const fullScreen = useMediaQuery('(max-width:600px)'); const { setUser } = useContext(UserContext); const [currentTab, setCurrentTab] = useState( @@ -68,21 +68,21 @@ const Login = ({ onClose }: LoginModalProps) => { > {!hasNoSocialMediaAuth ? ( ) : null} {!disablePasswords ? ( ) : null} {!disableAnonymous ? ( diff --git a/frontend/src/auth/modal/SocialAuth.tsx b/frontend/src/auth/modal/SocialAuth.tsx index d2a968b40..0f2cbbf3c 100644 --- a/frontend/src/auth/modal/SocialAuth.tsx +++ b/frontend/src/auth/modal/SocialAuth.tsx @@ -8,13 +8,14 @@ import { } from 'react-social-login-buttons'; import styled from '@emotion/styled'; import io, { Socket } from 'socket.io-client'; -import useTranslations, { useLanguage } from '../../translations'; -import { updateLanguage } from '../../api'; +import { useLanguage } from '../../translations'; +import { me, updateLanguage } from '../../api'; import { FullUser } from 'common'; import Wrapper from './Wrapper'; import SlackLoginButton from './social/SlackLoginButton'; import OktaLoginButton from './social/OktaLoginButton'; import useOAuthAvailabilities from '../../global/useOAuthAvailabilities'; +import { useTranslation } from 'react-i18next'; const API_URL = '/api/auth'; @@ -26,9 +27,9 @@ interface SocialAuthProps { function SocialAuth({ onClose, onUser }: SocialAuthProps) { const [socket, setSocket] = useState(null); const windowRef = useRef(null); - const { SocialMediaLogin: translations } = useTranslations(); + const { t } = useTranslation(); const { details } = useOAuthAvailabilities(); - const language = useLanguage(); + const [language] = useLanguage(); const handleOAuth = useCallback( (provider: string) => { const width = 600; @@ -64,7 +65,10 @@ function SocialAuth({ onClose, onUser }: SocialAuthProps) { const s = io(); setSocket(s); s.on('auth', async (_user: FullUser) => { - const updatedUser = await updateLanguage(language.value); + let updatedUser = await me(); + if (updatedUser?.language === null) { + updatedUser = await updateLanguage(language.locale); + } onUser(updatedUser); if (windowRef.current) { windowRef.current.close(); @@ -82,8 +86,8 @@ function SocialAuth({ onClose, onUser }: SocialAuthProps) { }, [onClose, onUser, language]); return ( - - {translations.info} + + {t('SocialMediaLogin.info')} {details.microsoft && ( diff --git a/frontend/src/auth/modal/account/Login.tsx b/frontend/src/auth/modal/account/Login.tsx index dae3c6de3..1646a49ca 100644 --- a/frontend/src/auth/modal/account/Login.tsx +++ b/frontend/src/auth/modal/account/Login.tsx @@ -2,7 +2,7 @@ import { useCallback, useState } from 'react'; import Button from '@mui/material/Button'; import CircularProgress from '@mui/material/CircularProgress'; import { Alert } from '@mui/material'; -import useTranslations from '../../../translations'; +import { useTranslation } from 'react-i18next'; import { FullUser } from 'common'; import Wrapper from './../Wrapper'; import Input from '../../../components/Input'; @@ -24,8 +24,7 @@ const Login = ({ onAskRegistration, onAskPasswordReset, }: LoginProps) => { - const { AccountLogin: translations, AuthCommon: authTranslations } = - useTranslations(); + const { t } = useTranslation(); const [loginEmail, setLoginEmail] = useState(''); const [loginPassword, setLoginPassword] = useState(''); const [error, setError] = useState(''); @@ -42,16 +41,16 @@ const Login = ({ onClose(); } } else { - setError(translations.errorEmailPasswordIncorrect!); + setError(t('AccountLogin.errorEmailPasswordIncorrect')!); } } } login(); - }, [loginEmail, loginPassword, translations, onClose, onUser]); + }, [loginEmail, loginPassword, t, onClose, onUser]); return ( : null} disabled={!loginEmail || !loginPassword || loading} > - {translations.loginButton} + {t('AccountLogin.loginButton')} } > - {translations.info} + {t('AccountLogin.info')} {!!error ? ( {error} @@ -73,8 +72,8 @@ const Login = ({ - {translations.registerLink} + {t('AccountLogin.registerLink')} - {translations.forgotPasswordLink} + {t('AccountLogin.forgotPasswordLink')} diff --git a/frontend/src/auth/modal/account/LostPassword.tsx b/frontend/src/auth/modal/account/LostPassword.tsx index 961c8e903..e74882c85 100644 --- a/frontend/src/auth/modal/account/LostPassword.tsx +++ b/frontend/src/auth/modal/account/LostPassword.tsx @@ -1,7 +1,7 @@ import { useCallback, useState } from 'react'; import Button from '@mui/material/Button'; import { Alert } from '@mui/material'; -import useTranslations from '../../../translations'; +import { useTranslation } from 'react-i18next'; import Wrapper from './../Wrapper'; import Input from '../../../components/Input'; import { Email } from '@mui/icons-material'; @@ -10,8 +10,7 @@ import { Link } from 'react-router-dom'; import useBackendCapabilities from '../../../global/useBackendCapabilities'; const LostPassword = () => { - const { ResetPassword: translations, AuthCommon: authTranslations } = - useTranslations(); + const { t } = useTranslation(); const [email, setEmail] = useState(''); const [done, setDone] = useState(false); const backend = useBackendCapabilities(); @@ -35,10 +34,10 @@ const LostPassword = () => { } return done ? ( - {translations.doneMessage} + {t('ResetPassword.doneMessage')} ) : ( { autoFocus disabled={!email.length} > - {translations.resetButton} + {t('ResetPassword.resetButton')} } > - {translations.info} + {t('ResetPassword.info')} void; @@ -29,9 +30,8 @@ const PasswordStrength = lazy( ); const Register = ({ onClose }: RegisterProps) => { - const { Register: translations, AuthCommon: authTranslations } = - useTranslations(); - const language = useLanguage(); + const { t } = useTranslation(); + const [language] = useLanguage(); const [registerName, setRegisterName] = useState(''); const [registerEmail, setRegisterEmail] = useState(''); const [registerPassword, setRegisterPassword] = useState(''); @@ -52,15 +52,15 @@ const Register = ({ onClose }: RegisterProps) => { registerName, registerEmail, registerPassword, - language.value + language.locale ); if (response.error) { switch (response.error) { case 'already-exists': - setGeneralError(translations.errorAlreadyRegistered!); + setGeneralError(t('Register.errorAlreadyRegistered')!); return; default: - setGeneralError(translations.errorGeneral!); + setGeneralError(t('Register.errorGeneral')!); return; } } else { @@ -74,8 +74,8 @@ const Register = ({ onClose }: RegisterProps) => { registerName, registerEmail, registerPassword, - language.value, - translations, + language.locale, + t, setUser, onClose, ]); @@ -91,7 +91,7 @@ const Register = ({ onClose }: RegisterProps) => { return ( { disabled={!validEmail || passwordScore < 3 || !validName} data-cy="register-button" > - {translations.registerButton} + {t('Register.registerButton')} ) : undefined } > {isSuccessful ? ( - {translations.messageSuccess} + {t('Register.messageSuccess')} ) : ( <> - {translations.info} + {t('Register.info')} {!!generalError ? ( @@ -121,8 +121,8 @@ const Register = ({ onClose }: RegisterProps) => { { { error={!validEmail && registerEmail.length > 0} helperText={ !validEmail && registerEmail.length > 0 - ? translations.errorInvalidEmail + ? t('Register.errorInvalidEmail') : undefined } data-cy="register-email" @@ -151,8 +151,8 @@ const Register = ({ onClose }: RegisterProps) => { { diff --git a/frontend/src/components/LanguagePicker.tsx b/frontend/src/components/LanguagePicker.tsx index 734b58c44..0c25e5ff4 100644 --- a/frontend/src/components/LanguagePicker.tsx +++ b/frontend/src/components/LanguagePicker.tsx @@ -28,9 +28,9 @@ const LanguagePicker = ({ value, onChange }: LanguagePickerProps) => { > {languages.map((language) => ( diff --git a/frontend/src/components/ProButton/index.tsx b/frontend/src/components/ProButton/index.tsx index d84e300bf..9cd4bf52a 100644 --- a/frontend/src/components/ProButton/index.tsx +++ b/frontend/src/components/ProButton/index.tsx @@ -13,10 +13,10 @@ import styled from '@emotion/styled'; import useIsPro from '../../auth/useIsPro'; import useIsDisabled from '../../hooks/useIsDisabled'; import useModal from '../../hooks/useModal'; -import useTranslation from '../../translations/useTranslations'; import { startTrial } from '../../views/subscribe/api'; import Feature from './Feature'; import { trackEvent } from '../../track'; +import { useTranslation } from 'react-i18next'; interface ComponentProp { disabled?: boolean; @@ -38,7 +38,7 @@ function ProButton({ children, quota }: ProButtonProps) { const [opened, open, close] = useModal(); const clone = isValid ? children : cloneElement(children, { onClick: open }); const navigate = useNavigate(); - const { SubscribeModal: translations } = useTranslation(); + const { t } = useTranslation(); const fullScreen = useMediaQuery('(max-width:600px)'); const goToSubscribe = useCallback( @@ -97,32 +97,42 @@ function ProButton({ children, quota }: ProButtonProps) { fullScreen={fullScreen} open={opened} > - {translations.title} + + {t('SubscribeModal.title')} + -
{translations.header}
+
{t('SubscribeModal.header')}
- {translations.description} + + {t('SubscribeModal.description')} + } color={colors.red[700]} - title={translations.features.encryptedSession.title!} - description={translations.features.encryptedSession.description!} + title={t('SubscribeModal.features.encryptedSession.title')!} + description={ + t('SubscribeModal.features.encryptedSession.description')! + } /> } color={colors.green[700]} - title={translations.features.privateSessions.title!} - description={translations.features.privateSessions.description!} + title={t('SubscribeModal.features.privateSessions.title')!} + description={ + t('SubscribeModal.features.privateSessions.description')! + } /> } color={colors.orange[700]} - title={translations.features.unlimitedPosts.title!} - description={translations.features.unlimitedPosts.description!} + title={t('SubscribeModal.features.unlimitedPosts.title')!} + description={ + t('SubscribeModal.features.unlimitedPosts.description')! + } /> @@ -133,12 +143,14 @@ function ProButton({ children, quota }: ProButtonProps) { color="secondary" onClick={handleStartTrial} > - {translations.startTrial} + {t('SubscribeModal.startTrial')} - + diff --git a/frontend/src/hooks/useFormatDate.ts b/frontend/src/hooks/useFormatDate.ts index 7b593af58..fb93318a4 100644 --- a/frontend/src/hooks/useFormatDate.ts +++ b/frontend/src/hooks/useFormatDate.ts @@ -18,7 +18,7 @@ export default function useFormatDate() { } export function useDateLocale() { - const language = useLanguage(); + const [language] = useLanguage(); const [locale, setLocale] = useState(() => englishLocale); useEffect(() => { diff --git a/frontend/src/index.tsx b/frontend/src/index.tsx index b0f05ac78..312cce1f0 100644 --- a/frontend/src/index.tsx +++ b/frontend/src/index.tsx @@ -1,6 +1,7 @@ import 'core-js/stable'; import 'whatwg-fetch'; import ReactDOM from 'react-dom'; +import './translations/i18n'; import App from './App'; import { initialiseAnalytics, initialiseSentry } from './track'; import * as serviceWorker from './serviceWorker'; diff --git a/frontend/src/state/columns.ts b/frontend/src/state/columns.ts index 6ec139d33..d35f668fe 100644 --- a/frontend/src/state/columns.ts +++ b/frontend/src/state/columns.ts @@ -1,14 +1,13 @@ import { ColumnDefinition, ColumnDefinitionType } from 'common'; -import { Translation } from '../translations'; import { v4 } from 'uuid'; import keyBy from 'lodash/keyBy'; -import { ColumnSettings, Template } from './types'; +import { ColumnSettings, Template, TranslationFunction } from './types'; import { getTemplate } from './templates'; import isEqual from 'lodash/isEqual'; export function buildDefaults( template: Template, - translations: Translation + translations: TranslationFunction ): ColumnSettings[] { const base = getTemplate(template, translations); return base; @@ -32,7 +31,7 @@ export function toColumnDefinitions( export function extrapolate( colDef: ColumnSettings, - translations: Translation + translations: TranslationFunction ): ColumnSettings { const defaults = getTemplateColumnByType(translations); const defaultDef = defaults(colDef.type); @@ -47,7 +46,7 @@ export function extrapolate( export function hasChanged( before: ColumnSettings[], after: ColumnSettings[], - translations: Translation + translations: TranslationFunction ) { const extrapolatedBefore = before.map((c) => extrapolate(c, translations)); const extrapolatedAfter = after.map((c) => extrapolate(c, translations)); @@ -55,103 +54,103 @@ export function hasChanged( } export const getTemplateColumnByType = - (translations: Translation) => (type: ColumnDefinitionType) => { + (t: TranslationFunction) => (type: ColumnDefinitionType) => { const dic = keyBy( [ { color: '#D1C4E9', icon: 'question', - label: translations.PostBoard.customQuestion, + label: t('PostBoard.customQuestion'), type: 'custom', }, { color: '#E8F5E9', icon: 'grinning', - label: translations.PostBoard.wellQuestion, + label: t('PostBoard.wellQuestion'), type: 'well', }, { color: '#FFEBEE', icon: 'unamused', - label: translations.PostBoard.notWellQuestion, + label: t('PostBoard.notWellQuestion'), type: 'notWell', }, { color: '#FFFDE7', icon: 'sunny', - label: translations.PostBoard.ideasQuestion, + label: t('PostBoard.ideasQuestion'), type: 'ideas', }, { color: '#E8F5E9', icon: 'arrow_forward', - label: translations.PostBoard.startQuestion, + label: t('PostBoard.startQuestion'), type: 'start', }, { color: '#FFEBEE', icon: 'black_square_for_stop', - label: translations.PostBoard.stopQuestion, + label: t('PostBoard.stopQuestion'), type: 'stop', }, { color: '#BBDEFB', icon: 'fast_forward', - label: translations.PostBoard.continueQuestion, + label: t('PostBoard.continueQuestion'), type: 'continue', }, { color: '#E8F5E9', icon: 'thumbsup', - label: translations.PostBoard.likedQuestion, + label: t('PostBoard.likedQuestion'), type: 'liked', }, { color: '#FFEBEE', icon: 'mortar_board', - label: translations.PostBoard.learnedQuestion, + label: t('PostBoard.learnedQuestion'), type: 'learned', }, { color: '#BBDEFB', icon: 'question', - label: translations.PostBoard.lackedQuestion, + label: t('PostBoard.lackedQuestion'), type: 'lacked', }, { color: '#E1BEE7', icon: 'desert_island', - label: translations.PostBoard.longedForQuestion, + label: t('PostBoard.longedForQuestion'), type: 'longedFor', }, { color: '#E8F5E9', icon: 'linked_paperclips', - label: translations.PostBoard.anchorQuestion, + label: t('PostBoard.anchorQuestion'), type: 'anchor', }, { color: '#FFEBEE', icon: 'motor_boat', - label: translations.PostBoard.boatQuestion, + label: t('PostBoard.boatQuestion'), type: 'cargo', }, { color: '#BBDEFB', icon: 'desert_island', - label: translations.PostBoard.islandQuestion, + label: t('PostBoard.islandQuestion'), type: 'island', }, { color: '#E1BEE7', icon: 'wind_blowing_face', - label: translations.PostBoard.windQuestion, + label: t('PostBoard.windQuestion'), type: 'wind', }, { color: '#FFE0B2', icon: 'moyai', - label: translations.PostBoard.rockQuestion, + label: t('PostBoard.rockQuestion'), type: 'rock', }, ] as ColumnSettings[], diff --git a/frontend/src/state/templates.ts b/frontend/src/state/templates.ts index 01908145c..ef05c4387 100644 --- a/frontend/src/state/templates.ts +++ b/frontend/src/state/templates.ts @@ -1,31 +1,33 @@ -import { Translation } from '../translations'; -import { Template, ColumnSettings, TemplateDefinition } from './types'; +import { + Template, + ColumnSettings, + TemplateDefinition, + TranslationFunction, +} from './types'; import { getTemplateColumnByType } from './columns'; -export function getAllTemplates( - translations: Translation -): TemplateDefinition[] { +export function getAllTemplates(t: TranslationFunction): TemplateDefinition[] { return [ { type: 'default', - name: translations.Template.default!, + name: t('Template.default')!, }, { type: 'well-not-well', - name: translations.Template.wellNotWell!, + name: t('Template.wellNotWell')!, }, { type: 'start-stop-continue', - name: translations.Template.startStopContinue!, + name: t('Template.startStopContinue')!, }, - { type: 'four-l', name: translations.Template.fourLs! }, - { type: 'sailboat', name: translations.Template.sailboat! }, + { type: 'four-l', name: t('Template.fourLs')! }, + { type: 'sailboat', name: t('Template.sailboat')! }, ]; } export function getTemplate( template: Template, - translations: Translation + translations: TranslationFunction ): ColumnSettings[] { const dic = getTemplateColumnByType(translations); switch (template) { diff --git a/frontend/src/state/types.ts b/frontend/src/state/types.ts index 0f2eec227..98269b481 100644 --- a/frontend/src/state/types.ts +++ b/frontend/src/state/types.ts @@ -1,4 +1,5 @@ import { ColumnDefinitionType } from 'common'; +import { Namespace, TFunction } from 'react-i18next'; export interface ColumnSettings { color: string; @@ -18,3 +19,5 @@ export interface TemplateDefinition { type: Template; name: string; } + +export type TranslationFunction = TFunction, undefined>; diff --git a/frontend/src/testing/index.tsx b/frontend/src/testing/index.tsx index ddfb49678..e418a2cef 100644 --- a/frontend/src/testing/index.tsx +++ b/frontend/src/testing/index.tsx @@ -46,7 +46,7 @@ export default function Inner({ children }: PropsWithChildren<{}>) { name: 'John Doe', photo: null, accountType: 'anonymous', - language: 'en', + language: 'en-GB', username: 'johndoe', email: 'john@doe.com', pro: false, @@ -68,7 +68,7 @@ export default function Inner({ children }: PropsWithChildren<{}>) { name: 'John Doe', photo: null, accountType: 'anonymous', - language: 'en', + language: 'en-GB', username: 'johndoe', email: 'john@doe.com', pro: false, diff --git a/frontend/src/translations/Context.tsx b/frontend/src/translations/Context.tsx deleted file mode 100644 index 01ef8062b..000000000 --- a/frontend/src/translations/Context.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { createContext } from 'react'; -import config from '../utils/getConfig'; - -const LanguageContext = createContext({ - language: config.defaultLanguage, - setLanguage: (_: string) => {}, -}); - -export default LanguageContext; diff --git a/frontend/src/translations/LanguageProvider.tsx b/frontend/src/translations/LanguageProvider.tsx index f795f2783..35574a41f 100644 --- a/frontend/src/translations/LanguageProvider.tsx +++ b/frontend/src/translations/LanguageProvider.tsx @@ -1,53 +1,16 @@ -import { - useState, - useEffect, - useCallback, - useContext, - PropsWithChildren, -} from 'react'; -import Context from './Context'; -import UserContext from '../auth/Context'; -import { TrackingEvent } from 'common'; -import { updateLanguage } from '../api'; -import { getItem, setItem } from '../utils/localStorage'; -import { trackEvent } from '../track'; +import { useEffect, PropsWithChildren } from 'react'; import useUser from '../auth/useUser'; -import config from '../utils/getConfig'; +import { useTranslation } from 'react-i18next'; export default function LanguageProvider({ children }: PropsWithChildren<{}>) { - const [language, setLanguage] = useState(config.defaultLanguage); const user = useUser(); - const { setUser } = useContext(UserContext); - - const handleChangeLanguage = useCallback( - async (language: string) => { - setLanguage(language); - setItem('language', language); - const updatedUser = await updateLanguage(language); - if (updatedUser) { - setUser(updatedUser); - } - }, - [setUser] - ); - - useEffect(() => { - const language = getItem('language'); - if (language) { - trackEvent(`language/change/${language}` as TrackingEvent); - setLanguage(language); - } - }, []); + const { i18n } = useTranslation(); useEffect(() => { if (user) { - setLanguage(user.language); + i18n.changeLanguage(user.language); } - }, [user]); + }, [user, i18n]); - return ( - - {children} - - ); + return <>{children}; } diff --git a/frontend/src/translations/ar.ts b/frontend/src/translations/ar.ts deleted file mode 100644 index bfe15a176..000000000 --- a/frontend/src/translations/ar.ts +++ /dev/null @@ -1,403 +0,0 @@ -import { Translation } from './types'; -export default { - Header: { - subtitle: 'أسلوب جيّد للتّوبيخ بطريقة مرنة ', - logout: 'خروج', - leave: 'غادر', - summaryMode: 'النّمط الملخّص', - account: undefined, - adminPanel: undefined, - }, - LanguagePicker: { - header: 'إختيار اللُّغة', - }, - Main: { - hint: 'يمكنُكَ دعوة أشخاص إلى هذه الجلسة عن طريق نسخ عنوان هذه الصفحة', - }, - Home: { - welcome: undefined, - }, - PreviousGame: { - createdBy: undefined, - posts: undefined, - participants: undefined, - votes: undefined, - actions: undefined, - }, - Column: { - createGroupTooltip: undefined, - }, - Group: { - emptyGroupTitle: '', - emptyGroupContent: '', - }, - Post: { - openExtra: undefined, - closeExtra: undefined, - vote: 'صوت', - votes: 'أصوات', - deleteButton: 'حذف', - setActionButton: undefined, - setGiphyButton: undefined, - noContent: '(هذا الموضوع فارغ)', - by: undefined, - upVote: undefined, - downVote: undefined, - voteRemainingMultiple: undefined, - voteRemainingOne: undefined, - voteRemainingNone: undefined, - toggleGiphyButton: undefined, - }, - Customize: { - title: undefined, - votingCategory: undefined, - votingCategorySub: undefined, - postCategory: undefined, - postCategorySub: undefined, - customTemplateCategory: undefined, - customTemplateCategorySub: undefined, - startButton: undefined, - editButton: undefined, - maxUpVotes: undefined, - maxUpVotesHelp: undefined, - maxDownVotes: undefined, - maxDownVotesHelp: undefined, - maxPosts: undefined, - maxPostsHelp: undefined, - allowSelfVoting: undefined, - allowSelfVotingHelp: undefined, - allowMultipleVotes: undefined, - allowMultipleVotesHelp: undefined, - allowActions: undefined, - allowActionsHelp: undefined, - allowAuthorVisible: undefined, - allowAuthorVisibleHelp: undefined, - newPostsFirst: undefined, - newPostsFirstHelp: undefined, - allowGiphy: undefined, - allowGiphyHelp: undefined, - allowGrouping: undefined, - allowGroupingHelp: undefined, - allowReordering: undefined, - allowReorderingHelp: undefined, - blurCards: undefined, - blurCardsHelp: undefined, - template: undefined, - templateHelp: undefined, - numberOfColumns: undefined, - numberOfColumnsHelp: undefined, - makeDefaultTemplate: undefined, - }, - PostBoard: { - customQuestion: undefined, - notWellQuestion: 'ما الذي يمكن تحسينه ؟', - wellQuestion: 'ما الذي فُعِلَ بنجاح؟', - ideasQuestion: 'هل من أيِّ فكرةٍ ذكيّة ؟', - startQuestion: undefined, - stopQuestion: undefined, - continueQuestion: undefined, - likedQuestion: undefined, - lackedQuestion: undefined, - learnedQuestion: undefined, - longedForQuestion: undefined, - anchorQuestion: undefined, - boatQuestion: undefined, - islandQuestion: undefined, - windQuestion: undefined, - rockQuestion: undefined, - disconnected: undefined, - reconnect: undefined, - notLoggedIn: undefined, - error: undefined, - maxPostsReached: undefined, - iAmDone: undefined, - iAmNotDoneYet: undefined, - userIsReady: undefined, - }, - GameMenu: { - board: undefined, - summary: undefined, - }, - Template: { - default: undefined, - wellNotWell: undefined, - startStopContinue: undefined, - fourLs: undefined, - sailboat: undefined, - }, - Clients: { - header: 'الضيوف الحاضرين معنا الآن:', - joined: undefined, - left: undefined, - }, - Join: { - welcome: ' ! مرحبا', - standardTab: { - header: 'موضوع جديد', - text: ': انقر أدناه و إبدء إعادة النظر', - button: 'إنشاء جلسة عمل جديدة', - customizeButton: undefined, - }, - optionsTab: { - header: 'أكثر', - input: 'عنوان', - button: 'إنشاء جلسة مخصصة', - }, - previousTab: { - header: 'الجلسات السابقة', - rejoinButton: 'الإنضمام', - }, - }, - AnonymousLogin: { - namePlaceholder: 'من أنت بالضبط؟ أدخل اسمك هنا', - buttonLabel: 'لنبدأ', - header: 'تسجيل الدخول', - anonymousAuthHeader: undefined, - anonymousAuthDescription: undefined, - authenticatingWith: undefined, - or: undefined, - }, - SocialMediaLogin: { - header: undefined, - info: undefined, - }, - AuthCommon: { - emailField: undefined, - passwordField: undefined, - nameField: undefined, - passwordScoreWords: undefined, - }, - AccountLogin: { - header: undefined, - loginButton: undefined, - info: undefined, - registerLink: undefined, - forgotPasswordLink: undefined, - errorEmailPasswordIncorrect: undefined, - }, - Register: { - header: undefined, - info: undefined, - registerButton: undefined, - errorAlreadyRegistered: undefined, - errorGeneral: undefined, - messageSuccess: undefined, - errorInvalidEmail: undefined, - }, - ValidateAccount: { - success: undefined, - error: undefined, - loading: undefined, - }, - ResetPassword: { - // Reset Modal - doneMessage: undefined, - header: undefined, - resetButton: undefined, - info: undefined, - // Reset Page - success: undefined, - error: undefined, - loading: undefined, - resetInfo: undefined, - }, - SummaryBoard: { - noPosts: 'لا توجد مشاركات للعرض', - copyAsMarkdown: undefined, - copyAsRichText: undefined, - copySuccessful: undefined, - }, - SessionName: { - defaultSessionName: 'جلسة جديدة', - }, - Invite: { - inviteButton: 'دعوة', - dialog: { - title: 'دعوة أشخاص إلى الجلسة', - text: 'لدعوة أشخاص إلى الجلسة يمكنك إرسال عنوان هذه الصفحة', - copyButton: 'نسخ العنوان', - }, - }, - Generic: { - ok: 'OK', - cancel: 'Cancel', - }, - Actions: { - tooltip: 'إنشاء إجراء على ظهر هذا العنصر', - label: 'افتح لوحة Action', - summaryTitle: 'أفعالك', - title: 'عمل', - }, - DeleteSession: { - header: undefined, - firstLine: undefined, - secondLine: undefined, - yesImSure: undefined, - cancel: undefined, - }, - RevealCards: { - buttonLabel: undefined, - dialogTitle: undefined, - dialogContent: undefined, - confirmButton: undefined, - cancelButton: undefined, - }, - AccountPage: { - anonymousError: undefined, - details: { - header: undefined, - username: undefined, - email: undefined, - accountType: undefined, - }, - plan: { - header: undefined, - plan: undefined, - youAreOwner: undefined, - youAreMember: undefined, - }, - subscription: { - header: undefined, - manageButton: undefined, - membersEditor: { - title: undefined, - limitReached: undefined, - info: undefined, - }, - }, - trial: { - header: undefined, - yourTrialWillExpireIn: undefined, - subscribe: undefined, - }, - deleteAccount: { - title: undefined, - warning: undefined, - deleteData: undefined, - modal: { - confirm: { - title: undefined, - description: undefined, - confirmation: undefined, - cancellation: undefined, - }, - subheader: undefined, - deleteAccount: undefined, - recommended: undefined, - deleteSessions: { - main: undefined, - selected: undefined, - unselected: undefined, - }, - deletePosts: { - main: undefined, - selected: undefined, - unselected: undefined, - }, - deleteVotes: { - main: undefined, - selected: undefined, - unselected: undefined, - }, - deleteAccountButton: undefined, - cancelButton: undefined, - }, - }, - }, - SubscribePage: { - alertAlreadyPro: undefined, - alertAlreadySubscribed: undefined, - currency: { - title: undefined, - description: undefined, - warning: undefined, - }, - plan: { - title: undefined, - description: undefined, - }, - domain: { - title: undefined, - description: undefined, - invalidDomain: undefined, - }, - subscribe: { - title: undefined, - description: undefined, - cannotRegisterWithAnon: undefined, - checkout: undefined, - }, - }, - SubscribeModal: { - title: undefined, - header: undefined, - description: undefined, - features: { - encryptedSession: { - title: undefined, - description: undefined, - }, - privateSessions: { - title: undefined, - description: undefined, - }, - unlimitedPosts: { - title: undefined, - description: undefined, - }, - }, - subscribeButton: undefined, - payButton: undefined, - cancelButton: undefined, - startTrial: undefined, - }, - Products: { - team: undefined, - unlimited: undefined, - 'self-hosted': undefined, - users: undefined, - unlimited_seats: undefined, - month: undefined, - year: undefined, - wantToPayYearly: undefined, - }, - Encryption: { - createEncryptedSession: undefined, - sessionNotEncrypted: undefined, - sessionEncryptedHaveKeyTooltip: undefined, - sessionEncryptedNoKeyTooltip: undefined, - sessionEncryptedWrongKeyTooltip: undefined, - newEncryptedSessionWarningTitle: undefined, - newEncryptedSessionWarningContent: undefined, - sessionEncryptionError: undefined, - passwordModalTitle: undefined, - passwordModelIncorrect: undefined, - }, - Private: { - lockSuccessNotification: undefined, - unlockSuccessNotification: undefined, - lockButton: undefined, - unlockButton: undefined, - lockDescription: undefined, - cancelButton: undefined, - sessionLockedTitle: undefined, - sessionLockedDescription: undefined, - sessionNonProTitle: undefined, - sessionNonProDescription: undefined, - sessionIsPublic: undefined, - sessionIsPrivate: undefined, - sessionIsPrivateNoAccess: undefined, - }, - TrialPrompt: { - allowanceReachedTitle: undefined, - allowanceReachedDescription: undefined, - nearEndAllowanceTitle: undefined, - nearEndAllowanceDescription: undefined, - onTrialTitle: undefined, - remainingTrialSentence: undefined, - trialEndedTitle: undefined, - trialEndedSentence: undefined, - subscribeNow: undefined, - }, - Chat: { writeAMessage: undefined }, -} as Translation; diff --git a/frontend/src/translations/de.ts b/frontend/src/translations/de.ts deleted file mode 100644 index 1c8e179bd..000000000 --- a/frontend/src/translations/de.ts +++ /dev/null @@ -1,410 +0,0 @@ -import { Translation } from './types'; -export default { - Header: { - subtitle: 'Ein schöner Weg auf eine agile Art zu meckern', - logout: 'Abmelden', - leave: 'Verlassen', - summaryMode: 'Zusammenfassungsmodus', - account: undefined, - adminPanel: undefined, - }, - LanguagePicker: { - header: 'Sprache auswählen', - }, - Main: { - hint: 'Du kannst Andere zu dieser Session einladen indem Du ihnen die URL schickst', - }, - Home: { - welcome: undefined, - }, - PreviousGame: { - createdBy: undefined, - posts: undefined, - participants: undefined, - votes: undefined, - actions: undefined, - }, - Column: { - createGroupTooltip: undefined, - }, - Group: { - emptyGroupTitle: '', - emptyGroupContent: '', - }, - Post: { - openExtra: undefined, - closeExtra: undefined, - vote: 'Stimme', - votes: 'Stimmen', - deleteButton: 'Löschen', - setActionButton: undefined, - setGiphyButton: undefined, - noContent: '(Dieser Post hat keinen Inhalt)', - by: 'von', - upVote: 'up-vote', - downVote: 'down-vote', - voteRemainingMultiple: (count: number, type: string) => - `Du hast ${count} ${type}s verbleibend.`, - voteRemainingOne: (type: string) => - `Du hast nur noch einen ${type} verbleibend, verteile ihn gut!`, - voteRemainingNone: (type: string) => `Du hast keine ${type}s verbleibend.`, - toggleGiphyButton: undefined, - }, - Customize: { - title: 'Personalisiere Dein Spiel', - votingCategory: 'Abstimmung', - votingCategorySub: 'Setze die Abstimmregeln', - postCategory: 'Beitragseinstellungen', - postCategorySub: 'Stelle ein, wie Nutzer mit Beitragen interagieren können', - customTemplateCategory: 'Spaltenkonfiguration', - customTemplateCategorySub: - 'Setze die Anzahl an Spalten und deren Eigenschaften', - startButton: 'Spiel starten!', - editButton: undefined, - maxUpVotes: 'Max Up-Votes', - maxUpVotesHelp: `Maximale Anzahl an 'up-votes', die ein Nutzer geben kann`, - maxDownVotes: 'Max Down-Votes', - maxDownVotesHelp: `Maximale Anzahl an 'down-votes', die ein Nutzer geben kann`, - maxPosts: undefined, - maxPostsHelp: undefined, - allowSelfVoting: 'Eigene Posts bewerten', - allowSelfVotingHelp: - 'Soll es Nutzern möglich sein eigene Beiträge zu bewerten?', - allowMultipleVotes: 'Mehrfachabstimmung', - allowMultipleVotesHelp: - 'Soll es Nutzern möglich sein mehrfach zu bewerten?', - allowActions: 'Erlaube Maßnahmen', - allowActionsHelp: `Bestimmt ob Maßnahmen hinzugefügt werden können`, - allowAuthorVisible: 'Zeige Author', - allowAuthorVisibleHelp: 'Zeigt den Author eines Posts an.', - newPostsFirst: undefined, - newPostsFirstHelp: undefined, - allowGiphy: undefined, - allowGiphyHelp: undefined, - allowGrouping: undefined, - allowGroupingHelp: undefined, - allowReordering: undefined, - allowReorderingHelp: undefined, - blurCards: undefined, - blurCardsHelp: undefined, - template: 'Vorlage', - templateHelp: 'Nutze ein vordefiniertes Spaltenset', - numberOfColumns: 'Anzahl an Spalten', - numberOfColumnsHelp: 'Setze die Anzahl an Spalten', - makeDefaultTemplate: undefined, - }, - PostBoard: { - customQuestion: 'Eigene Spalte', - notWellQuestion: 'Was können wir verbessern?', - wellQuestion: 'Was lief gut?', - ideasQuestion: 'Geniale Einfälle?', - startQuestion: 'Start', - stopQuestion: 'Stop', - continueQuestion: 'Weiter', - likedQuestion: 'Liked', - lackedQuestion: 'Lacked', - learnedQuestion: 'Learned', - longedForQuestion: 'Longed For', - anchorQuestion: 'Anker', - boatQuestion: 'Boot', - islandQuestion: 'Insel', - windQuestion: 'Wind', - rockQuestion: 'Fels', - disconnected: undefined, - reconnect: undefined, - notLoggedIn: undefined, - error: undefined, - maxPostsReached: undefined, - iAmDone: undefined, - iAmNotDoneYet: undefined, - userIsReady: undefined, - }, - GameMenu: { - board: undefined, - summary: undefined, - }, - Template: { - default: 'Default', - wellNotWell: 'Gut / Nicht Gut', - startStopContinue: 'Start / Stop / Weiter', - fourLs: 'Vier Ls', - sailboat: 'Segelboot', - }, - Clients: { - header: 'Mit dabei sind:', - joined: undefined, - left: undefined, - }, - Join: { - welcome: 'Willkommen zu Retrospected', - standardTab: { - header: 'Erstellen', - text: 'Klicke unten und starte deine Retrospektive:', - button: 'Erstelle eine neue Session', - customizeButton: 'Personalisieren', - }, - optionsTab: { - header: 'Optionen', - input: 'Name', - button: 'Erstelle eine personalisierte Session', - }, - previousTab: { - header: 'Letzte', - rejoinButton: 'Erneut beitreten', - }, - }, - AnonymousLogin: { - namePlaceholder: 'Wer genau bist Du? Gib hier Deinen Namen ein', - buttonLabel: 'Auf gehts!', - header: 'Anmelden', - anonymousAuthHeader: undefined, - anonymousAuthDescription: undefined, - authenticatingWith: undefined, - or: undefined, - }, - SocialMediaLogin: { - header: undefined, - info: undefined, - }, - AuthCommon: { - emailField: undefined, - passwordField: undefined, - nameField: undefined, - passwordScoreWords: undefined, - }, - AccountLogin: { - header: undefined, - loginButton: undefined, - info: undefined, - registerLink: undefined, - forgotPasswordLink: undefined, - errorEmailPasswordIncorrect: undefined, - }, - Register: { - header: undefined, - info: undefined, - registerButton: undefined, - errorAlreadyRegistered: undefined, - errorGeneral: undefined, - messageSuccess: undefined, - errorInvalidEmail: undefined, - }, - ValidateAccount: { - success: undefined, - error: undefined, - loading: undefined, - }, - ResetPassword: { - // Reset Modal - doneMessage: undefined, - header: undefined, - resetButton: undefined, - info: undefined, - // Reset Page - success: undefined, - error: undefined, - loading: undefined, - resetInfo: undefined, - }, - SummaryBoard: { - noPosts: 'Es gibt keine Beiträge', - copyAsMarkdown: undefined, - copyAsRichText: undefined, - copySuccessful: undefined, - }, - SessionName: { - defaultSessionName: 'Meine Retrospektive', - }, - Invite: { - inviteButton: 'Einladen', - dialog: { - title: 'Lade Andere in deine Retrospektive ein', - text: - 'Um Andere in deine Retrospektive einzuladen schicke ihnen einfach ' + - 'die folgende URL', - copyButton: 'URL in die Zwischenablage kopieren', - }, - }, - Generic: { - ok: 'OK', - cancel: 'Abbrechen', - }, - Actions: { - tooltip: 'Erstelle hierzu eine Maßnahme', - label: 'Öffne das Aktionspanel', - summaryTitle: 'Deine Maßnahmen', - title: 'Maßnahme', - }, - DeleteSession: { - header: undefined, - firstLine: undefined, - secondLine: undefined, - yesImSure: undefined, - cancel: undefined, - }, - RevealCards: { - buttonLabel: undefined, - dialogTitle: undefined, - dialogContent: undefined, - confirmButton: undefined, - cancelButton: undefined, - }, - AccountPage: { - anonymousError: undefined, - details: { - header: undefined, - username: undefined, - email: undefined, - accountType: undefined, - }, - plan: { - header: undefined, - plan: undefined, - youAreOwner: undefined, - youAreMember: undefined, - }, - subscription: { - header: undefined, - manageButton: undefined, - membersEditor: { - title: undefined, - limitReached: undefined, - info: undefined, - }, - }, - trial: { - header: undefined, - yourTrialWillExpireIn: undefined, - subscribe: undefined, - }, - deleteAccount: { - title: undefined, - warning: undefined, - deleteData: undefined, - modal: { - confirm: { - title: undefined, - description: undefined, - confirmation: undefined, - cancellation: undefined, - }, - subheader: undefined, - deleteAccount: undefined, - recommended: undefined, - deleteSessions: { - main: undefined, - selected: undefined, - unselected: undefined, - }, - deletePosts: { - main: undefined, - selected: undefined, - unselected: undefined, - }, - deleteVotes: { - main: undefined, - selected: undefined, - unselected: undefined, - }, - deleteAccountButton: undefined, - cancelButton: undefined, - }, - }, - }, - SubscribePage: { - alertAlreadyPro: undefined, - alertAlreadySubscribed: undefined, - currency: { - title: undefined, - description: undefined, - warning: undefined, - }, - plan: { - title: undefined, - description: undefined, - }, - domain: { - title: undefined, - description: undefined, - invalidDomain: undefined, - }, - subscribe: { - title: undefined, - description: undefined, - cannotRegisterWithAnon: undefined, - checkout: undefined, - }, - }, - SubscribeModal: { - title: undefined, - header: undefined, - description: undefined, - features: { - encryptedSession: { - title: undefined, - description: undefined, - }, - privateSessions: { - title: undefined, - description: undefined, - }, - unlimitedPosts: { - title: undefined, - description: undefined, - }, - }, - subscribeButton: undefined, - payButton: undefined, - cancelButton: undefined, - startTrial: undefined, - }, - Products: { - team: undefined, - unlimited: undefined, - 'self-hosted': undefined, - users: undefined, - unlimited_seats: undefined, - month: undefined, - year: undefined, - wantToPayYearly: undefined, - }, - Encryption: { - createEncryptedSession: undefined, - sessionNotEncrypted: undefined, - sessionEncryptedHaveKeyTooltip: undefined, - sessionEncryptedNoKeyTooltip: undefined, - sessionEncryptedWrongKeyTooltip: undefined, - newEncryptedSessionWarningTitle: undefined, - newEncryptedSessionWarningContent: undefined, - sessionEncryptionError: undefined, - passwordModalTitle: undefined, - passwordModelIncorrect: undefined, - }, - Private: { - lockSuccessNotification: undefined, - unlockSuccessNotification: undefined, - lockButton: undefined, - unlockButton: undefined, - lockDescription: undefined, - cancelButton: undefined, - sessionLockedTitle: undefined, - sessionLockedDescription: undefined, - sessionNonProTitle: undefined, - sessionNonProDescription: undefined, - sessionIsPublic: undefined, - sessionIsPrivate: undefined, - sessionIsPrivateNoAccess: undefined, - }, - TrialPrompt: { - allowanceReachedTitle: undefined, - allowanceReachedDescription: undefined, - nearEndAllowanceTitle: undefined, - nearEndAllowanceDescription: undefined, - onTrialTitle: undefined, - remainingTrialSentence: undefined, - trialEndedTitle: undefined, - trialEndedSentence: undefined, - subscribeNow: undefined, - }, - Chat: { writeAMessage: undefined }, -} as Translation; diff --git a/frontend/src/translations/en.ts b/frontend/src/translations/en.ts deleted file mode 100644 index 7d8901019..000000000 --- a/frontend/src/translations/en.ts +++ /dev/null @@ -1,485 +0,0 @@ -import { WsErrorType } from 'common'; -import { Translation } from './types'; -import { plural } from './utils'; -export default { - Header: { - subtitle: 'A good way of expressing oneself in an Agile way', - logout: 'Logout', - leave: 'Leave', - summaryMode: 'Summary Mode', - account: 'My Account', - adminPanel: 'Administration Panel', - }, - LanguagePicker: { - header: 'Choose a language', - }, - Main: { - hint: 'You can invite others to this session by copy-pasting the URL', - }, - Home: { - welcome: (userName: string) => `Welcome, ${userName}`, - }, - PreviousGame: { - createdBy: 'Created by', - posts: plural('post'), - participants: plural('participant'), - votes: plural('vote'), - actions: plural('action'), - }, - Column: { - createGroupTooltip: 'Create a group to group posts together', - }, - Group: { - emptyGroupTitle: 'This is an empty group', - emptyGroupContent: 'Move a post here to fill this group', - }, - Post: { - openExtra: 'Additional features', - closeExtra: 'Close', - vote: 'vote', - votes: 'votes', - deleteButton: 'Delete', - setActionButton: 'Set Action', - setGiphyButton: 'Choose a Giphy image', - noContent: '(This post has no content)', - by: 'by', - upVote: 'up-vote', - downVote: 'down-vote', - voteRemainingMultiple: (count: number, type: string) => - `You have ${count} ${type}s remaining.`, - voteRemainingOne: (type: string) => - `You only have one ${type} remaining, make it count!`, - voteRemainingNone: (type: string) => - `You don't have any ${type} remaining.`, - toggleGiphyButton: 'Toggle Giphy image', - }, - Customize: { - title: 'Customise your Session', - votingCategory: 'Voting', - votingCategorySub: 'Set the rules about likes and dislikes', - postCategory: 'Post settings', - postCategorySub: - 'Set the rules about what a user can do when creating or viewing a post', - customTemplateCategory: 'Column Template', - customTemplateCategorySub: - 'Set the number of columns and their characteristics', - startButton: 'Start the session', - editButton: 'Update', - maxUpVotes: 'Max Up-Votes', - maxUpVotesHelp: `Maximum number of 'likes' votes a user is allowed to cast`, - maxDownVotes: 'Max Down-Votes', - maxDownVotesHelp: `Maximum number of 'dislikes' votes a user is allowed to cast`, - maxPosts: `Max Posts per user`, - maxPostsHelp: `Maximum number of posts a user can create per session`, - allowSelfVoting: 'Allow Self Voting', - allowSelfVotingHelp: 'Whether to allow a user to vote on their own post', - allowMultipleVotes: 'Allow Multiple Votes', - allowMultipleVotesHelp: - 'Whether to allow a user to vote multiple times on the same post', - allowActions: 'Allow Actions', - allowActionsHelp: `Whether to allow the 'Action' (follow-up) field on each post`, - allowAuthorVisible: 'Show Author', - allowAuthorVisibleHelp: - 'Display the author of the post, on the post itself.', - newPostsFirst: 'Add new posts first', - newPostsFirstHelp: 'New posts are added at the top of the column', - allowGiphy: 'Allow Giphy', - allowGiphyHelp: 'Allow users to set a Giphy image against a post', - allowGrouping: 'Allow Grouping', - allowGroupingHelp: 'Allow the creation of groups to group posts together', - allowReordering: 'Allow Re-ordering', - allowReorderingHelp: 'Allow re-ordering posts by drag-and-drop', - blurCards: 'Blur Cards', - blurCardsHelp: - 'Cards content is blurred until the moderator reveals the content', - template: 'Template', - templateHelp: 'Use a pre-defined set of columns', - numberOfColumns: 'Number of columns', - numberOfColumnsHelp: 'Set the number of columns', - makeDefaultTemplate: 'Make this my default template', - }, - PostBoard: { - customQuestion: 'Custom Column', - notWellQuestion: 'What could be improved?', - wellQuestion: 'What went well?', - ideasQuestion: 'A brilliant idea to share?', - startQuestion: 'Start', - stopQuestion: 'Stop', - continueQuestion: 'Continue', - likedQuestion: 'Liked', - lackedQuestion: 'Lacked', - learnedQuestion: 'Learned', - longedForQuestion: 'Longed For', - anchorQuestion: 'Anchor', - boatQuestion: 'Boat', - islandQuestion: 'Island', - windQuestion: 'Wind', - rockQuestion: 'Rock', - disconnected: 'You have been disconnected from the current session.', - reconnect: 'Reconnect', - notLoggedIn: - 'You are not logged in. You can view this session as a spectator, but must login to participate.', - error: (error: WsErrorType) => { - switch (error) { - case 'action_unauthorised': - return 'You are not allowed to perform this action.'; - case 'cannot_edit_group': - return 'Editing the group failed.'; - case 'cannot_edit_post': - return 'Editing the post failed.'; - case 'cannot_get_session': - return 'Could not get the session data. Please reload the page.'; - case 'cannot_register_vote': - return 'Your vote was not registered successfully.'; - case 'cannot_save_group': - return 'The group you created could not be saved.'; - case 'cannot_save_post': - return 'The post you created could not be saved.'; - case 'cannot_delete_group': - return 'The group could not be deleted'; - case 'cannot_delete_post': - return 'The post could not be deleted'; - case 'cannot_rename_session': - return 'Renaming the session failed'; - case 'cannot_save_columns': - return 'Saving columns failed'; - case 'cannot_save_options': - return 'Saving options failed'; - default: - return 'An unknown error happened'; - } - }, - maxPostsReached: `You have reached the maximum number of posts set by the moderator.`, - iAmDone: "I'm done!", - iAmNotDoneYet: "I'm not done yet...", - userIsReady: (user) => `${user} is ready!`, - }, - GameMenu: { - board: 'Board', - summary: 'Summary', - }, - Template: { - default: 'Default', - wellNotWell: 'Well / Not Well', - startStopContinue: 'Start / Stop / Continue', - fourLs: 'Four Ls', - sailboat: 'Sailboat', - }, - Clients: { - header: 'Participants:', - joined: (users: string) => `${users} joined.`, - left: (users: string) => `${users} left.`, - }, - Join: { - welcome: 'Welcome to Retrospected', - standardTab: { - header: 'Create', - text: 'Click below and start retrospecting:', - button: 'Create a new session', - customizeButton: 'Customise', - }, - optionsTab: { - header: 'Options', - input: 'Name', - button: 'Create custom session', - }, - previousTab: { - header: 'Previous', - rejoinButton: 'Rejoin', - }, - }, - AnonymousLogin: { - namePlaceholder: 'Please enter a name or nickname here to continue', - buttonLabel: 'Login', - header: 'Login', - anonymousAuthHeader: 'Anonymous Login', - anonymousAuthDescription: - "This will create an anonymous account. Some features won't be available.", - authenticatingWith: 'Authenticating with', - or: 'or', - }, - SocialMediaLogin: { - header: 'OAuth', - info: 'This will use a third party provider of your choosing to authenticate you. No password is stored.', - }, - AuthCommon: { - emailField: 'E-mail', - passwordField: 'Password', - nameField: 'Your name (for display purposes)', - passwordScoreWords: ['weak', 'weak', 'not quite', 'good', 'strong'], - }, - AccountLogin: { - header: 'Password', - loginButton: 'Login', - info: 'Login with your email and password.', - registerLink: 'Not registered? Click here', - forgotPasswordLink: 'Forgot your password?', - errorEmailPasswordIncorrect: 'Your credentials are incorrect.', - }, - Register: { - header: 'Register', - info: 'Get yourself a Retrospected account!', - registerButton: 'Register', - errorAlreadyRegistered: 'This email is already registered', - errorGeneral: 'An error occurred while trying to create your account.', - messageSuccess: - 'Thank you! You should receive an email shortly to validate your account.', - errorInvalidEmail: 'Please enter a valid email', - }, - ValidateAccount: { - success: `Your email has been correctly validated. I'm going to log you in in a sec!`, - error: 'There was an error validating your email.', - loading: 'We are validating your email. Please wait.', - }, - ResetPassword: { - // Reset Modal - doneMessage: - 'Done! Have a look in your emails, you should get a link to reset your password.', - header: 'Password Reset', - resetButton: 'Reset Password', - info: `Forgot your password? Not a problem. Enter your email below and you'll get a reset email prompto.`, - // Reset Page - success: `Your password has been updated. I'm going to log you in in a sec!`, - error: 'There was an error updating your password.', - loading: 'We are updating your password. Please wait.', - resetInfo: 'Please provide a new password', - }, - SummaryBoard: { - noPosts: 'There are no posts to display', - copyAsMarkdown: 'Copy the summary as Markdown', - copyAsRichText: 'Copy the summary as Rich Text', - copySuccessful: 'You successfully copied your summary in your clipboard', - }, - SessionName: { - defaultSessionName: 'My Retrospective', - }, - Invite: { - inviteButton: 'Invite', - dialog: { - title: 'Invite people to your retrospective', - text: - 'To invite people to your retrospected session, simply send them ' + - 'the following URL', - copyButton: 'Copy URL to Clipboard', - }, - }, - Generic: { - ok: 'OK', - cancel: 'Cancel', - }, - Actions: { - tooltip: 'Create an action on the back of this item', - label: 'Open the Action panel', - summaryTitle: 'Your Actions', - title: 'Action', - }, - DeleteSession: { - header: (name) => `Deleting "${name}" ?`, - firstLine: - 'Deleting a session is irreversible. It will delete all posts, votes, groups, and the session itself. The data cannot be restored.', - secondLine: - 'Are you sure you want to delete this session and all its content?', - yesImSure: `Yes, I'm sure`, - cancel: `No, I'm sorry, I made a mistake`, - }, - RevealCards: { - buttonLabel: 'Reveal', - dialogTitle: 'Reveal all cards', - dialogContent: - 'This will reveal all blurred cards for everyone. This cannot be undone.', - confirmButton: `Let's reveal!`, - cancelButton: 'No thanks', - }, - AccountPage: { - anonymousError: `Anonymous accounts cannot have access to their profile (because they don't have one).`, - details: { - header: 'Your Details', - username: 'Username', - email: 'Email', - accountType: 'Account Type', - }, - plan: { - header: 'Your Plan', - plan: 'Plan', - youAreOwner: - 'You are the owner of this plan, through the subscription below.', - youAreMember: `You are on this plan through somebody else's subscription.`, - }, - subscription: { - header: 'Your Subscription', - manageButton: 'Manage my subscription', - membersEditor: { - title: 'Your Team', - limitReached: (limit) => - `You reached the limit of your subscription (${limit} users, including yourself). Please remove members, or upgrade to an unlimited Company account.`, - info: ( - limit - ) => `Add emails below to grant Pro accounts to up to ${limit} other - colleagues. Press Enter after each email address.`, - }, - }, - trial: { - header: `Your Trial`, - yourTrialWillExpireIn: (date: string) => - `Your trial will end in ${date}.`, - subscribe: `Subscribe now`, - }, - deleteAccount: { - title: 'GDPR', - warning: - 'You have the right to be forgotten. That being said, be careful when deleting your account. This cannot be undone.', - deleteData: 'Delete my data', - modal: { - confirm: { - title: 'Are you absolutely sure?', - description: 'There is no going back on this.', - confirmation: 'Yes I want to delete all my data', - cancellation: 'Get me out of here', - }, - subheader: 'Choose what to delete', - deleteAccount: - 'Delete your account and any identities linked to your email.', - recommended: 'Recommended', - deleteSessions: { - main: 'Should we delete the sessions (retrospectives) you have created?', - selected: - "Your sessions and all their data, including other people's posts and votes, will be permanently deleted.", - unselected: - 'Your sessions will be kept and their author will become an anonymous user.', - }, - deletePosts: { - main: 'Should we delete all the posts you wrote?', - selected: - 'Your posts, in any session, and their associated votes and actions will be permanently deleted.', - unselected: - 'Your posts will be kept, but they will become associated with an anonymous user.', - }, - deleteVotes: { - main: 'Should we also delete all your votes?', - selected: 'Your votes, in all sessions will be permanently deleted.', - unselected: - 'Your votes will be kept, but they will become associated with an anonymous user.', - }, - deleteAccountButton: 'DELETE YOUR ACCOUNT', - cancelButton: 'Cancel', - }, - }, - }, - SubscribePage: { - alertAlreadyPro: `You already are a Pro user, so you might not need another subscription.`, - alertAlreadySubscribed: `You already have a subscription, so you might not need another subscription.`, - currency: { - title: 'Currency', - description: 'Pick a currency you would like to be billed with', - warning: (currency: string) => - `Your account is already set to use ${currency}, so you cannot change the currency anymore.`, - }, - plan: { - title: 'Plan', - description: 'Choose the plan that fits your use case!', - }, - domain: { - title: 'Domain', - description: - 'Your unlimited subscription applies to a given domain. Any user with this email domain will automatically become a Pro user.', - invalidDomain: - 'Please provide a valid domain. The domain cannot be a free or disposable email domain.', - }, - subscribe: { - title: 'Checkout', - description: 'You will be redirected to our partner, Stripe, for payment', - cannotRegisterWithAnon: - 'You need to be logged in with an OAuth or Password account to continue.', - checkout: 'Checkout', - }, - }, - SubscribeModal: { - title: 'Pro Subscription', - header: 'Retrospected Pro', - description: `Protect your company's data by subscribing to Retrospected Pro. With Retrospected Pro, get the following features and more:`, - features: { - encryptedSession: { - title: 'Encrypted Sessions', - description: - 'Your data is encrypted in your browser, making any decryption impossible on the Retrospected server.', - }, - privateSessions: { - title: 'Private Sessions', - description: - 'Make sure only authorised people can access your session.', - }, - unlimitedPosts: { - title: 'Unlimited Posts', - description: 'With a Pro subscription, get unlimited posts.', - }, - }, - subscribeButton: 'Subscribe', - payButton: 'Select', - cancelButton: 'Cancel', - startTrial: '30-day Trial', - }, - Products: { - team: 'Perfect for smaller teams, you can select up to 20 colleagues who will be upgraded to a Pro account.', - unlimited: - 'If you are a bigger company, you will enjoy an unlimited number of Pro accounts.', - 'self-hosted': - 'Retrospected on premises, one-time fee and unlimited updates. Keep total control of your data, for ever.', - users: (users: number) => `${users} users`, - unlimited_seats: 'Unlimited', - month: 'month', - year: 'year', - wantToPayYearly: - 'I want to pay annually (every 12 months), and get one month free per year!', - }, - Encryption: { - createEncryptedSession: 'Encrypted Session', - sessionNotEncrypted: 'This session is not encrypted.', - sessionEncryptedHaveKeyTooltip: `This session is encrypted, and the key is stored in your browser. You can open this session without having to provide the password again.`, - sessionEncryptedNoKeyTooltip: - 'This session is encrypted, and the key is not stored in your browser. You will be asked for the decryption key when opening this session.', - sessionEncryptedWrongKeyTooltip: `This session is encrypted, and the key you have stored is not the correct key.`, - newEncryptedSessionWarningTitle: `This session is encrypted locally`, - newEncryptedSessionWarningContent: (key: string) => - `It is very important for you to save the full URL (which contains the key) somewhere safe, or at least the encryption key: ${key}. If you lose this encryption key, there is nothing that can be done to retrieve the data.`, - sessionEncryptionError: `This session is encrypted, and you don't seem to have the decryption key stored locally. Please use the original link, including the decryption key.`, - passwordModalTitle: `Encrypted Session - Enter Password`, - passwordModelIncorrect: `The encryption key is incorrect.`, - }, - Private: { - lockSuccessNotification: - 'Your session has been successfuly made private. No new participants can join.', - unlockSuccessNotification: - 'Your session has been successfuly made public. Anyone can join.', - lockButton: 'Make Private', - unlockButton: 'Make Public', - lockDescription: - 'You are about to make the session private. Only the current participants (listed below) will be allowed access to this session once locked.', - cancelButton: 'Cancel', - sessionLockedTitle: 'This session is private.', - sessionLockedDescription: - 'Please ask its moderator to unlock it so you can join. Then, refresh this page.', - sessionNonProTitle: 'This session is only accessible to Pro users', - sessionNonProDescription: - 'This session uses features only available to Pro users. Please ask the moderator or subscription holder to give you a Pro account.', - sessionIsPublic: 'This session is public and accessible to anyone.', - sessionIsPrivate: 'This session is private, and you have access.', - sessionIsPrivateNoAccess: - 'This session is private, but you do not have access.', - }, - TrialPrompt: { - allowanceReachedTitle: 'You have reached your free allowance', - allowanceReachedDescription: `In order to get unlimited posts, please subscribe to Retrospected Pro`, - nearEndAllowanceTitle: 'You are nearing the end of your quota', - nearEndAllowanceDescription: (quota) => - `You have about ${quota} posts left`, - onTrialTitle: 'Retrospected Pro - Trial', - remainingTrialSentence: (remaining) => - `You have ${remaining} left on your trial.`, - trialEndedTitle: 'Your Retrospected Pro Trial has ended', - trialEndedSentence: 'Subscribe today to regain access to the Pro features.', - subscribeNow: 'Subscribe now!', - }, - Chat: { - writeAMessage: 'Write a message here...', - }, -} as Translation; diff --git a/frontend/src/translations/es.ts b/frontend/src/translations/es.ts deleted file mode 100644 index 891698d2f..000000000 --- a/frontend/src/translations/es.ts +++ /dev/null @@ -1,406 +0,0 @@ -import { Translation } from './types'; -export default { - Header: { - subtitle: 'Una buena manera de despotricar ordenadamente', - logout: 'Cerrar sesión', - leave: 'Salir', - summaryMode: 'Modo resumido', - account: undefined, - adminPanel: undefined, - }, - LanguagePicker: { - header: 'Escoje un idioma', - }, - Main: { - hint: 'Puedes invitar a otros a esta sesión compartiendo la URL', - }, - Home: { - welcome: undefined, - }, - PreviousGame: { - createdBy: undefined, - posts: undefined, - participants: undefined, - votes: undefined, - actions: undefined, - }, - Column: { - createGroupTooltip: undefined, - }, - Group: { - emptyGroupTitle: '', - emptyGroupContent: '', - }, - Post: { - openExtra: undefined, - closeExtra: undefined, - vote: 'vote', - votes: 'votos', - deleteButton: 'Suprimir', - setActionButton: undefined, - setGiphyButton: undefined, - noContent: '(Esta publicacion no tiene contenido)', - by: undefined, - upVote: undefined, - downVote: undefined, - voteRemainingMultiple: undefined, - voteRemainingOne: undefined, - voteRemainingNone: undefined, - toggleGiphyButton: undefined, - }, - Customize: { - title: undefined, - votingCategory: undefined, - votingCategorySub: undefined, - postCategory: undefined, - postCategorySub: undefined, - customTemplateCategory: undefined, - customTemplateCategorySub: undefined, - startButton: undefined, - editButton: undefined, - maxUpVotes: undefined, - maxUpVotesHelp: undefined, - maxDownVotes: undefined, - maxDownVotesHelp: undefined, - maxPosts: undefined, - maxPostsHelp: undefined, - allowSelfVoting: undefined, - allowSelfVotingHelp: undefined, - allowMultipleVotes: undefined, - allowMultipleVotesHelp: undefined, - allowActions: undefined, - allowActionsHelp: undefined, - allowAuthorVisible: undefined, - allowAuthorVisibleHelp: undefined, - newPostsFirst: undefined, - newPostsFirstHelp: undefined, - allowGiphy: undefined, - allowGiphyHelp: undefined, - allowGrouping: undefined, - allowGroupingHelp: undefined, - allowReordering: undefined, - allowReorderingHelp: undefined, - blurCards: undefined, - blurCardsHelp: undefined, - template: undefined, - templateHelp: undefined, - numberOfColumns: undefined, - numberOfColumnsHelp: undefined, - makeDefaultTemplate: undefined, - }, - PostBoard: { - customQuestion: undefined, - notWellQuestion: 'Qué se podría mejorar?', - wellQuestion: 'Qué ha ido bien?', - ideasQuestion: 'Una brillante idea que compartir?', - startQuestion: undefined, - editButton: undefined, - stopQuestion: undefined, - continueQuestion: undefined, - likedQuestion: undefined, - lackedQuestion: undefined, - learnedQuestion: undefined, - longedForQuestion: undefined, - anchorQuestion: undefined, - boatQuestion: undefined, - islandQuestion: undefined, - windQuestion: undefined, - rockQuestion: undefined, - disconnected: undefined, - reconnect: undefined, - notLoggedIn: undefined, - error: undefined, - maxPostsReached: undefined, - iAmDone: undefined, - iAmNotDoneYet: undefined, - userIsReady: undefined, - }, - GameMenu: { - board: undefined, - summary: undefined, - }, - Template: { - default: undefined, - wellNotWell: undefined, - startStopContinue: undefined, - fourLs: undefined, - sailboat: undefined, - }, - Clients: { - header: 'Acompañenos amablemente en este momento:', - joined: undefined, - left: undefined, - }, - Join: { - welcome: 'Bienvenido a la retrospectiva', - standardTab: { - header: 'Crear una sesión', - text: 'Pulse abajo y empieze la retrospectiva:', - button: 'Crear una sesión nueva', - customizeButton: undefined, - }, - optionsTab: { - header: 'Avanzado', - input: 'inserte un nombre para su sesión', - button: 'Crear una sesión personalizada', - }, - previousTab: { - header: 'Sesiones anteriores', - rejoinButton: 'Reunirse', - }, - }, - AnonymousLogin: { - namePlaceholder: 'Quién eres exáctamente? Inserta tu nombre aquí', - buttonLabel: 'Empezemos', - header: 'Login', - anonymousAuthHeader: undefined, - anonymousAuthDescription: undefined, - authenticatingWith: undefined, - or: undefined, - }, - SocialMediaLogin: { - header: undefined, - info: undefined, - }, - AuthCommon: { - emailField: undefined, - passwordField: undefined, - nameField: undefined, - passwordScoreWords: undefined, - }, - AccountLogin: { - header: undefined, - loginButton: undefined, - info: undefined, - registerLink: undefined, - forgotPasswordLink: undefined, - errorEmailPasswordIncorrect: undefined, - }, - Register: { - header: undefined, - info: undefined, - registerButton: undefined, - errorAlreadyRegistered: undefined, - errorGeneral: undefined, - messageSuccess: undefined, - errorInvalidEmail: undefined, - }, - ValidateAccount: { - success: undefined, - error: undefined, - loading: undefined, - }, - ResetPassword: { - // Reset Modal - doneMessage: undefined, - header: undefined, - resetButton: undefined, - info: undefined, - // Reset Page - success: undefined, - error: undefined, - loading: undefined, - resetInfo: undefined, - }, - SummaryBoard: { - noPosts: 'No hay publicaciones que mostrar', - copyAsMarkdown: undefined, - copyAsRichText: undefined, - copySuccessful: undefined, - }, - SessionName: { - defaultSessionName: 'Mi retrospectiva', - }, - Invite: { - inviteButton: 'Invitar', - dialog: { - title: 'Invitar personas a tu retrospectiva', - text: - 'Para invitar otras personas a tu retrospectiva, sencillamente enviales ' + - 'la siguiente URL.', - copyButton: 'Copiar la URL al Portapapeles', - }, - }, - Generic: { - ok: 'Ok', - cancel: 'Cancelar', - }, - Actions: { - tooltip: 'Crear una acción', - label: 'Abre el panel de acción.', - summaryTitle: 'Tus acciones', - title: 'Acción', - }, - DeleteSession: { - header: undefined, - firstLine: undefined, - secondLine: undefined, - yesImSure: undefined, - cancel: undefined, - }, - RevealCards: { - buttonLabel: undefined, - dialogTitle: undefined, - dialogContent: undefined, - confirmButton: undefined, - cancelButton: undefined, - }, - AccountPage: { - anonymousError: undefined, - details: { - header: undefined, - username: undefined, - email: undefined, - accountType: undefined, - }, - plan: { - header: undefined, - plan: undefined, - youAreOwner: undefined, - youAreMember: undefined, - }, - subscription: { - header: undefined, - manageButton: undefined, - membersEditor: { - title: undefined, - limitReached: undefined, - info: undefined, - }, - }, - trial: { - header: undefined, - yourTrialWillExpireIn: undefined, - subscribe: undefined, - }, - deleteAccount: { - title: undefined, - warning: undefined, - deleteData: undefined, - modal: { - confirm: { - title: undefined, - description: undefined, - confirmation: undefined, - cancellation: undefined, - }, - subheader: undefined, - deleteAccount: undefined, - recommended: undefined, - deleteSessions: { - main: undefined, - selected: undefined, - unselected: undefined, - }, - deletePosts: { - main: undefined, - selected: undefined, - unselected: undefined, - }, - deleteVotes: { - main: undefined, - selected: undefined, - unselected: undefined, - }, - deleteAccountButton: undefined, - cancelButton: undefined, - }, - }, - }, - SubscribePage: { - alertAlreadyPro: undefined, - alertAlreadySubscribed: undefined, - currency: { - title: undefined, - description: undefined, - warning: undefined, - }, - plan: { - title: undefined, - description: undefined, - }, - domain: { - title: undefined, - description: undefined, - invalidDomain: undefined, - }, - subscribe: { - title: undefined, - description: undefined, - cannotRegisterWithAnon: undefined, - checkout: undefined, - }, - }, - SubscribeModal: { - title: undefined, - header: undefined, - description: undefined, - features: { - encryptedSession: { - title: undefined, - description: undefined, - }, - privateSessions: { - title: undefined, - description: undefined, - }, - unlimitedPosts: { - title: undefined, - description: undefined, - }, - }, - subscribeButton: undefined, - payButton: undefined, - cancelButton: undefined, - startTrial: undefined, - }, - Products: { - team: undefined, - unlimited: undefined, - 'self-hosted': undefined, - users: undefined, - unlimited_seats: undefined, - month: undefined, - year: undefined, - wantToPayYearly: undefined, - }, - Encryption: { - createEncryptedSession: undefined, - sessionNotEncrypted: undefined, - sessionEncryptedHaveKeyTooltip: undefined, - sessionEncryptedNoKeyTooltip: undefined, - sessionEncryptedWrongKeyTooltip: undefined, - newEncryptedSessionWarningTitle: undefined, - newEncryptedSessionWarningContent: undefined, - sessionEncryptionError: undefined, - passwordModalTitle: undefined, - passwordModelIncorrect: undefined, - }, - Private: { - lockSuccessNotification: undefined, - unlockSuccessNotification: undefined, - lockButton: undefined, - unlockButton: undefined, - lockDescription: undefined, - cancelButton: undefined, - sessionLockedTitle: undefined, - sessionLockedDescription: undefined, - sessionNonProTitle: undefined, - sessionNonProDescription: undefined, - sessionIsPublic: undefined, - sessionIsPrivate: undefined, - sessionIsPrivateNoAccess: undefined, - }, - TrialPrompt: { - allowanceReachedTitle: undefined, - allowanceReachedDescription: undefined, - nearEndAllowanceTitle: undefined, - nearEndAllowanceDescription: undefined, - onTrialTitle: undefined, - remainingTrialSentence: undefined, - trialEndedTitle: undefined, - trialEndedSentence: undefined, - subscribeNow: undefined, - }, - Chat: { writeAMessage: undefined }, -} as Translation; diff --git a/frontend/src/translations/fr.ts b/frontend/src/translations/fr.ts deleted file mode 100644 index 70adda974..000000000 --- a/frontend/src/translations/fr.ts +++ /dev/null @@ -1,481 +0,0 @@ -import { WsErrorType } from 'common'; -import { Translation } from './types'; -import { plural } from './utils'; -export default { - Header: { - subtitle: "Un bon moyen de s'exprimer de façon Agile", - logout: 'Déconnexion', - leave: 'Sortir', - summaryMode: 'Mode Résumé', - account: 'Mon compte', - adminPanel: 'Gestion des utilisateurs', - }, - LanguagePicker: { - header: 'Changez de langue', - }, - Main: { - hint: "Vous pouvez inviter d'autres participants en leur envoyant l'URL de cette page", - }, - Home: { - welcome: (userName: string) => `Bienvenue, ${userName}`, - }, - PreviousGame: { - createdBy: 'Créé par', - posts: plural('post'), - participants: plural('participant'), - votes: plural('vote'), - actions: plural('action'), - }, - Column: { - createGroupTooltip: 'Créer un groupe', - }, - Group: { - emptyGroupTitle: 'Ce groupe est vide', - emptyGroupContent: 'Déplacez un post ici pour le remplir', - }, - Post: { - openExtra: 'Fonctions supplémentaires', - closeExtra: 'Fermer', - vote: 'vote', - votes: 'votes', - deleteButton: 'Supprimer', - setActionButton: 'Définir une action', - setGiphyButton: 'Choisir une image Giphy', - noContent: '(Aucun contenu)', - by: 'par', - upVote: 'positif', - downVote: 'négatif', - voteRemainingMultiple: (count: number, type: string) => - `Il vous reste ${count} votes ${type}s.`, - voteRemainingOne: (type: string) => - `Il ne vous reste plus qu'un vote ${type}, ne le gâchez pas !`, - voteRemainingNone: (type: string) => - `Il ne vous reste plus aucun vote ${type}.`, - toggleGiphyButton: "Montrer/Cacher l'image Giphy", - }, - Customize: { - title: 'Nouvelle session personalisée', - votingCategory: 'Votes', - votingCategorySub: 'Règles concernant les votes', - postCategory: 'Options des posts', - postCategorySub: `Règles concernant ce qu'un utilisateur peut faire sur un post`, - customTemplateCategory: 'Colonnes personalisées', - customTemplateCategorySub: - 'Personnalisez vos colonnes et leur caractéristiques', - startButton: 'Lancez la session', - maxUpVotes: 'Nb de votes max (positifs)', - maxUpVotesHelp: `Réglez le nombre de votes positifs maximum qu'un participant peut mettre dans une session`, - maxDownVotes: 'Nb de votes max (négatifs)', - maxDownVotesHelp: `Réglez le nombre de votes négatifs maximum qu'un participant peut mettre dans une session`, - maxPosts: `Nb de posts max`, - maxPostsHelp: `Nombre maximum de posts qu'un participant peut créer par session`, - allowSelfVoting: 'Voter pour soi', - allowSelfVotingHelp: 'Autoriser à voter pour ses propres posts', - allowMultipleVotes: 'Votes multiples', - allowMultipleVotesHelp: - 'Autoriser à voter plusieurs fois pour le même post', - allowActions: 'Activer les Actions', - allowActionsHelp: - 'Autoriser un utilisateur à entrer une action sur un post', - allowAuthorVisible: "Afficher l'auteur", - allowAuthorVisibleHelp: `Afficher l'auteur du post sur le post lui-même.`, - newPostsFirst: `Nouveaux posts en premier`, - newPostsFirstHelp: - 'Les nouveaux posts sont ajoutés en haut de chaque colonne', - allowGiphy: 'Activer Giphy', - allowGiphyHelp: - "Autoriser les utilisateurs à ajouter une image Giphy sur n'importe quel post", - allowGrouping: 'Groupes', - allowGroupingHelp: - 'Permettre aux utilisateurs de grouper les posts par groupes', - allowReordering: 'Re-organiser', - allowReorderingHelp: - "Permettre aux utilisateurs de réorganiser l'ordre des posts", - blurCards: 'Flouter', - blurCardsHelp: `Les posts sont floutés, jusqu'à ce qu'un modérateur révèle les posts`, - template: 'Règles prédéfinies', - templateHelp: 'Sélectionnez un jeu de colonnes prédéfini', - numberOfColumns: 'Nombre de colonnes', - numberOfColumnsHelp: 'Réglez le nombre de colonnes', - makeDefaultTemplate: 'En faire mes réglages par défaut', - }, - PostBoard: { - customQuestion: 'Question Additionelle', - notWellQuestion: 'Des améliorations ?', - wellQuestion: "Qu'est-ce qui s'est bien passé ?", - ideasQuestion: 'Une bonne idée à partager ?', - startQuestion: 'Commencer', - editButton: 'Mettre à jour', - stopQuestion: 'Arrêter', - continueQuestion: 'Continuer', - likedQuestion: 'Aimé', - lackedQuestion: 'A manqué', - learnedQuestion: 'Appris', - longedForQuestion: 'A hâte de', - anchorQuestion: 'Ancre', - boatQuestion: 'Bateau', - islandQuestion: 'Île', - windQuestion: 'Vent', - rockQuestion: 'Rocher', - disconnected: 'Vous avez été déconnecté de la session.', - reconnect: 'Se reconnecter', - notLoggedIn: - "Vous n'êtes pas connecté. Vous pouvez regarder cette session en tant que spectateur, mais vous devez vous connecter pour participer.", - error: (error: WsErrorType) => { - switch (error) { - case 'action_unauthorised': - return `Vous n'avez pas la permission de performer cette action.`; - case 'cannot_edit_group': - return 'La modification de ce groupe à échoué.'; - case 'cannot_edit_post': - return 'La modification de ce post à échoué'; - case 'cannot_get_session': - return 'Impossible de charger les données de cette session.'; - case 'cannot_register_vote': - return `Votre vote n'a pas été enregistré.`; - case 'cannot_save_group': - return `Le groupe que vous avez créé n'a pas pu être enregistré correctement.`; - case 'cannot_save_post': - return `Le post que vous avez créé n'a pas pu être enregistré correctement.`; - case 'cannot_delete_group': - return 'Le groupe ne peut être supprimé'; - case 'cannot_delete_post': - return 'Le post ne peut être supprimé'; - case 'cannot_rename_session': - return 'La session ne peut être renommée'; - case 'cannot_save_columns': - return `Les colonnes n'ont pu être enregistrées`; - case 'cannot_save_options': - return `Les options n'ont pu être enregistrées`; - default: - return 'Une erreur inconnue est survenue'; - } - }, - maxPostsReached: `Vous avez atteint le nombre de posts maximum prévu par le modérateur.`, - iAmDone: "J'ai fini !", - iAmNotDoneYet: "Je n'ai pas encore fini...", - userIsReady: (user) => `${user} est prêt !`, - }, - GameMenu: { - board: 'Board', // Si qqn à une suggestion de traduction... - summary: 'Résumé', - }, - Template: { - default: 'Par défaut', - wellNotWell: 'Bien / Pas Bien', - startStopContinue: 'Commencer / Arrêter / Continuer', - fourLs: 'Les 4 A', - sailboat: 'Bateau', - }, - Clients: { - header: 'Participants:', - joined: (users: string) => `${users} connecté.`, - left: (users: string) => `${users} déconnecté.`, - }, - Join: { - welcome: 'Bienvenue', - standardTab: { - header: 'Créer', - text: 'Cliquez ci-dessous et commencez à retrospecter:', - button: 'Nouvelle session', - customizeButton: 'Personnaliser', - }, - optionsTab: { - header: 'Options', - input: 'Donnez un nom à votre session', - button: 'Créer une session personalisée', - }, - previousTab: { - header: 'Précédentes', - rejoinButton: 'Rejoindre', - }, - }, - AnonymousLogin: { - namePlaceholder: 'Votre nom, ou pseudonyme', - buttonLabel: 'Se connecter', - header: 'Se connecter', - anonymousAuthHeader: 'Identification Anonyme', - anonymousAuthDescription: - 'Ceci va créer un compte anonyme, certaines fonctionalitées ne seront pas disponibles.', - authenticatingWith: 'Identification avec', - or: 'ou', - }, - SocialMediaLogin: { - header: 'OAuth', - info: 'Un service tiers de votre choix va vous permettre de vous authentifier. Aucun mot de passe ne sera stocké.', - }, - AuthCommon: { - emailField: 'Adresse e-mail', - passwordField: 'Mot de passe', - nameField: 'Votre nom (ou pseudo)', - passwordScoreWords: [ - 'faible', - 'faible', - 'encore un effort', - 'suffisant', - 'très bien!', - ], - }, - AccountLogin: { - header: 'Mot de Passe', - loginButton: 'Se connecter', - info: 'Connectez-vous avec votre email et votre mot de passe.', - registerLink: 'Pas de compte ? Cliquez ici', - forgotPasswordLink: 'Mot de passe oublié ?', - errorEmailPasswordIncorrect: - 'Les identifiants communiqués sont incorrects.', - }, - Register: { - header: `S'enregistrer`, - info: 'Enregistrez un nouveau compte Retrospected.', - registerButton: 'Créer un compte', - errorAlreadyRegistered: 'Désolé, cet email est déjà enregistré', - errorGeneral: 'Une error est survenue lors de la création de votre compte.', - messageSuccess: - 'Merci ! Vous devriez reçevoir un email pour valider votre compte.', - errorInvalidEmail: `Merci d'entrer un email valide`, - }, - ValidateAccount: { - success: `Votre email a été validé. Ne bougez pas, je vous connecte dans quelques secondes.`, - error: - 'Une erreur est survenue lors de la validation de votre adresse e-mail.', - loading: 'Nous validons votre e-mail... Merci de votre patience.', - }, - ResetPassword: { - // Reset Modal - doneMessage: `C'est fait ! Jetez un oeuil dans votre boîte email, vous devriez reçevoir un email pour mettre à jour votre mot de passe.`, - header: 'Changer de mot de passe', - resetButton: 'Mettre à jour', - info: 'Vous avez oublié votre mot de passe ? Pas de problème, entrez votre email et vous recevrez un email en retour.', - // Reset Page - success: `Votre mot de passe a été mis à jour. Je vais vous connecter dans quelques secondes.`, - error: - 'Une erreur est survenue lors de la mise à jour de votre mot de passe.', - loading: 'Nous mettons votre mot de passe à jour. Merci de patienter.', - resetInfo: 'Merci de choisir un nouveau mot de passe:', - }, - SummaryBoard: { - noPosts: 'Aucun post à afficher', - copyAsMarkdown: 'Copier le résumé au format Markdown', - copyAsRichText: 'Copier le résumé en texte enrichi', - copySuccessful: 'Vous avez copié le résumé avec succès', - }, - SessionName: { - defaultSessionName: 'Ma Retrospective', - }, - Invite: { - inviteButton: 'Inviter', - dialog: { - title: 'Invitez des participants à votre retrospective', - text: - 'Pour inviter des participants à votre session retrospected, ' + - 'envoyez leur le lien suivant', - copyButton: 'Copier', - }, - }, - Generic: { - ok: 'Ok', - cancel: 'Annuler', - }, - Actions: { - tooltip: 'Créer une action relative à ce commentaire', - label: 'Ajouter une action', - summaryTitle: 'Vos Actions', - title: 'Action', - }, - DeleteSession: { - header: (name) => `Supprimer "${name}" ?`, - firstLine: - 'Effacer une session est irreversible. Tout les posts, groupes, votes et la session elle-même vont être effacés. Les données ne peuvent être récupérée.', - secondLine: - 'Êtes-vous certain(e) de vouloir effaçer cette session et son contenu ?', - yesImSure: `Oui, j'en suis sûr`, - cancel: 'Non, je me suis trompé(e)', - }, - RevealCards: { - buttonLabel: 'Révéler', - dialogTitle: 'Révéler tous les posts', - dialogContent: `Cela va révéler (déflouter) tout les posts. L'opération n'est pas reversible.`, - confirmButton: `Révéler`, - cancelButton: 'Non merci', - }, - AccountPage: { - anonymousError: `Les comptes anonymes ne peuvent avoir accès à leur profile (puisque ils n'en ont pas).`, - details: { - header: 'Vos Coordonnées', - username: `Nom d'utilisateur`, - email: 'E-Mail', - accountType: 'Type de compte', - }, - plan: { - header: 'Votre Accès', - plan: 'Accès', - youAreOwner: `Vous êtes l'administrateur de cet abonnement. Vous pouvez le gérer via la section ci-dessous.`, - youAreMember: `Vous devez votre accès Pro grâce à l'abonnement d'un tiers.`, - }, - subscription: { - header: 'Votre Abonnement', - manageButton: 'Gérer mon abonnement', - membersEditor: { - title: 'Votre Equipe', - limitReached: (limit) => - `Vous avez atteint le nombre maximum de membres (${limit}) permis par votre abonnement. Vous pouvez passer à l'abonnement Company pour un nombre de collaborateur illimité.`, - info: (limit) => - `Ajouter des addresses emails ci-dessous pour donner un accès Pro à vos collaborateurs (dans la limite de ${limit} collaborateurs). Appuyez sur Entrée après chaque email.`, - }, - }, - trial: { - header: `Votre Periode d'Essai`, - yourTrialWillExpireIn: (date: string) => - `Votre période d'essai va se terminer dans ${date}.`, - subscribe: `S'abonner`, - }, - deleteAccount: { - title: 'GDPR', - warning: - "Vous avez le droit à l'oubli. Cela étant dit, effacer vos données est définitif.", - deleteData: 'Effacer mes données', - modal: { - confirm: { - title: 'Êtes-vous absolument certain(e) ?', - description: "Cette opération n'est pas réversible !", - confirmation: 'Oui, je veux effaçer toutes mes données', - cancellation: "J'ai changé d'avis !", - }, - subheader: 'Choisir quoi effacer', - deleteAccount: - 'Effacer votre compte ainsi que toutes les identités liées à votre email.', - recommended: 'Recommandé', - deleteSessions: { - main: 'Effacer les sessions (les rétrospectives) que vous avez créées ?', - selected: - "Vos sessions, and toutes les données associées (incluant les posts et votes d'autres personnes) seront éffacées de manière permanente et irréversible.", - unselected: - 'Vos sessions seront conservées, et leur auteur deviendra un auteur anonyme.', - }, - deletePosts: { - main: 'Effacer les posts que vous avez écris ?', - selected: - "Vos posts, dans n'importe quelle session, ainsi que les votes associés, seront effacés de manière permanente et irreversible.", - unselected: - 'Vos posts seront conservés, mais leur auteur deviendra un compte anonyme.', - }, - deleteVotes: { - main: 'Effacer vos votes ?', - selected: "Vos votes, dans n'importe quelle session, seront effacés.", - unselected: 'Vos votes seront conservés, et deviendront anonymes.', - }, - deleteAccountButton: 'SUPPRIMER VOTRE COMPTE', - cancelButton: 'Annuler', - }, - }, - }, - SubscribePage: { - alertAlreadyPro: `Vous avez déjà un compte Pro, vous n'avez peut-être donc pas besoin d'un abonnement supplémentaire.`, - alertAlreadySubscribed: `Vous avez déjà un abonnement, vous n'avez peut-être donc pas besoin d'un abonnement supplémentaire.`, - currency: { - title: 'Devise', - description: 'Choisissez une devise de facturation.', - warning: (currency: string) => - `Votre compte est déjà en ${currency}, vous ne pouvez donc plus en changer.`, - }, - plan: { - title: 'Abonnement', - description: `Choisissez l'abonnement qui vous convient`, - }, - domain: { - title: 'Nom de domaine', - description: `Votre abonnement illimité est basé sur le nom de domaine de votre email. Tout utilisateur dont l'email contient ce nom de domaine sera automatiquement un utilisateur Pro.`, - invalidDomain: `Merci d'entrer un nom de domaine valide. Les noms de domaines d'emails gratuits ne sont pas valides.`, - }, - subscribe: { - title: 'Payer', - description: `Vous serez redirigé vers notre partenaire Stripe. Aucune coordonnées bancaire n'est stockée par Retrospected.`, - cannotRegisterWithAnon: `Vous devez être connecté avec un compte OAuth ou Classique (mot de passe) avant de continuer.`, - checkout: 'Payer', - }, - }, - SubscribeModal: { - title: 'Abonnement Pro', - header: 'Retrospected Pro', - description: `Protégez les données de votre entreprise en vous abonnant à Retrospected Pro. Avec Retrospected Pro, bénéficiez des fonctionalités suivantes:`, - features: { - encryptedSession: { - title: 'Session Cryptées', - description: - 'Vos données sont cryptées localement, sur votre navigateur, les rendant impossible à déchiffrer sur le serveur.', - }, - privateSessions: { - title: 'Session Privées', - description: - 'Assurez-vous que seules les personnes choisies puissent accéder à votre session.', - }, - unlimitedPosts: { - title: 'Posts illimités', - description: 'Nombre de posts illimité avec Retrospected Pro.', - }, - }, - subscribeButton: `S'abonner`, - payButton: 'Selectionner', - cancelButton: `Annuler`, - startTrial: `Essai 30 jours`, - }, - Products: { - team: `Parfait pour une équipe, vous pouvez sélectioner jusqu'à 20 collègues qui recevront un compte Retrospected Pro.`, - unlimited: `Si vous avez besoin de plus, l'abonnement "Pro Unlimited" vous donnera un nombre de compte Pro illimité`, - 'self-hosted': - 'Installez Retrospected sur vos serveurs. Gardez le contrôle total de vos données, et profitez des mise-à-jours illimitées.', - users: (users: number) => `${users} utilisateurs`, - unlimited_seats: 'Illimité', - month: 'mois', - year: 'an', - wantToPayYearly: - 'Je souhaite payer annuellement, et obtenir un mois gratuit par an !', - }, - Encryption: { - createEncryptedSession: 'Session cryptée', - sessionNotEncrypted: `Cette session n'est pas cryptée`, - sessionEncryptedHaveKeyTooltip: `Cette session est chiffrée, et la clef est stockée dans votre navigateur. Vous pouvez ouvrir cette session sans avoir à en donner le mot de passe.`, - sessionEncryptedNoKeyTooltip: `Cette session est chiffrée, et la clef n'a pas été trouvée dans votre navigateur. Il vous sera demandé de donner le mot de passe lors de l'ouverture de cette session.`, - sessionEncryptedWrongKeyTooltip: `Cette session est chiffrée, et la clef qui est stockée dans votre navigateur n'est pas la bonne.`, - newEncryptedSessionWarningTitle: `Cette session est chiffrée localement`, - newEncryptedSessionWarningContent: (key: string) => - `Il est très important de sauvegarder l'URL complète de cette page (qui contient la clef de chiffrement). Le cas échéant, vous pouvez également sauvegarder la clef elle-même (${key}). Si vous perdez cette clef, il vous sera impossible de récupérer vos données.`, - sessionEncryptionError: `Cette session est cryptée, et vous ne semblez pas avoir la clef de chiffrement dans votre navigateur. Merci d'utiliser le lien complet qui vous a été donné lors de la création de cette session.`, - passwordModalTitle: `Session chiffrée - Saisie du mot de passe`, - passwordModelIncorrect: `Le mot de passe (ou clef de chiffrement) est incorrect.`, - }, - Private: { - lockSuccessNotification: - 'La session a été correctement privatisée. Aucun nouveau participant ne pourra y accéder.', - unlockSuccessNotification: 'La session a été correctement rendue publique.', - lockButton: 'Rendre privée', - unlockButton: 'Rendre publique', - lockDescription: `Vous êtes sur le point de privatiser la session. Seuls les utilisateurs ayant déjà accédé à cette session (dont la liste s'affiche ci-dessous) pourront accéder à cette session une fois vérouillée.`, - cancelButton: 'Annuler', - sessionLockedTitle: 'Cette session est privée.', - sessionLockedDescription: - 'Demandez à votre modérateur de la rendre publique pour que vous puissiez la rejoindre. Ensuite, rafraichissez la page.', - sessionNonProTitle: `Cette session n'est accessible qu'aux utilisateurs Pro.`, - sessionNonProDescription: `Cette session n'est ouverte qu'aux détenteurs d'un compte Retrospected Pro. Vous pouvez demander au modérateur ou au gérant de l'abonnement Pro de vous donner un accès.`, - sessionIsPublic: - 'Cette session est publique, et accessible à tout le monde.', - sessionIsPrivate: 'Cette session est privée, et vous y avez accès.', - sessionIsPrivateNoAccess: `Cette session est privée, mais vous n'y avez pas accès.`, - }, - TrialPrompt: { - allowanceReachedTitle: 'Vous avez atteint la limite de posts gratuits', - allowanceReachedDescription: - 'Inscrivez-vous à Retrospected Pro pour passer en illimité', - nearEndAllowanceTitle: 'Vous approchez la limite de posts gratuits', - nearEndAllowanceDescription: (quota) => - `Vous avez environ ${quota} posts restants.`, - onTrialTitle: `Retrospected Pro - Période d'essai`, - remainingTrialSentence: (remaining) => - `Vous avez ${remaining} restant sur votre période d'essai.`, - trialEndedTitle: `Votre période d'essai Retrospected Pro est terminée`, - trialEndedSentence: `Abonnez-vous aujourd'hui pour continuer à bénéficier des avantages de la version Pro.`, - subscribeNow: `Je m'abonne`, - }, - Chat: { writeAMessage: 'Écrivez un message ici...' }, -} as Translation; diff --git a/frontend/src/translations/hu.ts b/frontend/src/translations/hu.ts deleted file mode 100644 index 15769d224..000000000 --- a/frontend/src/translations/hu.ts +++ /dev/null @@ -1,406 +0,0 @@ -import { Translation } from './types'; -export default { - Header: { - subtitle: 'Panaszkodjunk rendezetten', - logout: 'Kijelentkezés', - leave: 'Távozás', - summaryMode: 'Összesített mód', - account: undefined, - adminPanel: undefined, - }, - LanguagePicker: { - header: 'Válassz nyelvet', - }, - Main: { - hint: 'Ha meg akarsz hívni másokat, másold ki és oszd meg velük az URL-t', - }, - Home: { - welcome: undefined, - }, - PreviousGame: { - createdBy: undefined, - posts: undefined, - participants: undefined, - votes: undefined, - actions: undefined, - }, - Column: { - createGroupTooltip: undefined, - }, - Group: { - emptyGroupTitle: '', - emptyGroupContent: '', - }, - Post: { - openExtra: undefined, - closeExtra: undefined, - vote: 'szavazat', - votes: 'szavazat', - deleteButton: 'törlés', - setActionButton: undefined, - setGiphyButton: undefined, - noContent: '(This post has no content)', - by: undefined, - upVote: undefined, - downVote: undefined, - voteRemainingMultiple: undefined, - voteRemainingOne: undefined, - voteRemainingNone: undefined, - toggleGiphyButton: undefined, - }, - Customize: { - title: undefined, - votingCategory: undefined, - votingCategorySub: undefined, - postCategory: undefined, - postCategorySub: undefined, - customTemplateCategory: undefined, - customTemplateCategorySub: undefined, - startButton: undefined, - editButton: undefined, - maxUpVotes: undefined, - maxUpVotesHelp: undefined, - maxDownVotes: undefined, - maxDownVotesHelp: undefined, - maxPosts: undefined, - maxPostsHelp: undefined, - allowSelfVoting: undefined, - allowSelfVotingHelp: undefined, - allowMultipleVotes: undefined, - allowMultipleVotesHelp: undefined, - allowActions: undefined, - allowActionsHelp: undefined, - allowAuthorVisible: undefined, - allowAuthorVisibleHelp: undefined, - newPostsFirst: undefined, - newPostsFirstHelp: undefined, - allowGiphy: undefined, - allowGiphyHelp: undefined, - allowGrouping: undefined, - allowGroupingHelp: undefined, - allowReordering: undefined, - allowReorderingHelp: undefined, - blurCards: undefined, - blurCardsHelp: undefined, - template: undefined, - templateHelp: undefined, - numberOfColumns: undefined, - numberOfColumnsHelp: undefined, - makeDefaultTemplate: undefined, - }, - PostBoard: { - customQuestion: undefined, - notWellQuestion: 'Mit lehetne jobban csinálni?', - wellQuestion: 'Mit ment jól?', - ideasQuestion: 'Van valami nagyszerű ötleted?', - startQuestion: undefined, - editButton: undefined, - stopQuestion: undefined, - continueQuestion: undefined, - likedQuestion: undefined, - lackedQuestion: undefined, - learnedQuestion: undefined, - longedForQuestion: undefined, - anchorQuestion: undefined, - boatQuestion: undefined, - islandQuestion: undefined, - windQuestion: undefined, - rockQuestion: undefined, - disconnected: undefined, - reconnect: undefined, - notLoggedIn: undefined, - error: undefined, - maxPostsReached: undefined, - iAmDone: undefined, - iAmNotDoneYet: undefined, - userIsReady: undefined, - }, - GameMenu: { - board: undefined, - summary: undefined, - }, - Template: { - default: undefined, - wellNotWell: undefined, - startStopContinue: undefined, - fourLs: undefined, - sailboat: undefined, - }, - Clients: { - header: 'Jelenleg itt van:', - joined: undefined, - left: undefined, - }, - Join: { - welcome: 'Üdv, ez itt a Retrospected', - standardTab: { - header: 'Ülés létrehozása', - text: 'Kattints ide a kezdéshez:', - button: 'Új ülés indítása', - customizeButton: undefined, - }, - optionsTab: { - header: 'Haladó', - input: 'Adj nevet az ülésnek', - button: 'Ülés létrehozása', - }, - previousTab: { - header: 'Previous sessions', - rejoinButton: 'Rejoin', - }, - }, - AnonymousLogin: { - namePlaceholder: 'Hogy is hívnak? Kérlek írd ide a nevedet', - buttonLabel: 'Kezdjük', - header: 'Login', - anonymousAuthHeader: undefined, - anonymousAuthDescription: undefined, - authenticatingWith: undefined, - or: undefined, - }, - SocialMediaLogin: { - header: undefined, - info: undefined, - }, - AuthCommon: { - emailField: undefined, - passwordField: undefined, - nameField: undefined, - passwordScoreWords: undefined, - }, - AccountLogin: { - header: undefined, - loginButton: undefined, - info: undefined, - registerLink: undefined, - forgotPasswordLink: undefined, - errorEmailPasswordIncorrect: undefined, - }, - Register: { - header: undefined, - info: undefined, - registerButton: undefined, - errorAlreadyRegistered: undefined, - errorGeneral: undefined, - messageSuccess: undefined, - errorInvalidEmail: undefined, - }, - ValidateAccount: { - success: undefined, - error: undefined, - loading: undefined, - }, - ResetPassword: { - // Reset Modal - doneMessage: undefined, - header: undefined, - resetButton: undefined, - info: undefined, - // Reset Page - success: undefined, - error: undefined, - loading: undefined, - resetInfo: undefined, - }, - SummaryBoard: { - noPosts: 'There are no posts to display', - copyAsMarkdown: undefined, - copyAsRichText: undefined, - copySuccessful: undefined, - }, - SessionName: { - defaultSessionName: 'My Retrospective', - }, - Invite: { - inviteButton: 'Invite', - dialog: { - title: 'Invite people to your retrospective', - text: - 'To invite people to your retrospected session, simply send them ' + - 'the following URL', - copyButton: 'Copy URL to Clipboard', - }, - }, - Generic: { - ok: 'OK', - cancel: 'Megszünteti', - }, - Actions: { - tooltip: 'Hozzon létre egy műveletet az elem hátoldalán', - label: 'Nyissa meg a Művelet panelt', - summaryTitle: 'Az Ön tevékenységei', - title: 'Akció', - }, - DeleteSession: { - header: undefined, - firstLine: undefined, - secondLine: undefined, - yesImSure: undefined, - cancel: undefined, - }, - RevealCards: { - buttonLabel: undefined, - dialogTitle: undefined, - dialogContent: undefined, - confirmButton: undefined, - cancelButton: undefined, - }, - AccountPage: { - anonymousError: undefined, - details: { - header: undefined, - username: undefined, - email: undefined, - accountType: undefined, - }, - plan: { - header: undefined, - plan: undefined, - youAreOwner: undefined, - youAreMember: undefined, - }, - subscription: { - header: undefined, - manageButton: undefined, - membersEditor: { - title: undefined, - limitReached: undefined, - info: undefined, - }, - }, - trial: { - header: undefined, - yourTrialWillExpireIn: undefined, - subscribe: undefined, - }, - deleteAccount: { - title: undefined, - warning: undefined, - deleteData: undefined, - modal: { - confirm: { - title: undefined, - description: undefined, - confirmation: undefined, - cancellation: undefined, - }, - subheader: undefined, - deleteAccount: undefined, - recommended: undefined, - deleteSessions: { - main: undefined, - selected: undefined, - unselected: undefined, - }, - deletePosts: { - main: undefined, - selected: undefined, - unselected: undefined, - }, - deleteVotes: { - main: undefined, - selected: undefined, - unselected: undefined, - }, - deleteAccountButton: undefined, - cancelButton: undefined, - }, - }, - }, - SubscribePage: { - alertAlreadyPro: undefined, - alertAlreadySubscribed: undefined, - currency: { - title: undefined, - description: undefined, - warning: undefined, - }, - plan: { - title: undefined, - description: undefined, - }, - domain: { - title: undefined, - description: undefined, - invalidDomain: undefined, - }, - subscribe: { - title: undefined, - description: undefined, - cannotRegisterWithAnon: undefined, - checkout: undefined, - }, - }, - SubscribeModal: { - title: undefined, - header: undefined, - description: undefined, - features: { - encryptedSession: { - title: undefined, - description: undefined, - }, - privateSessions: { - title: undefined, - description: undefined, - }, - unlimitedPosts: { - title: undefined, - description: undefined, - }, - }, - subscribeButton: undefined, - payButton: undefined, - cancelButton: undefined, - startTrial: undefined, - }, - Products: { - team: undefined, - unlimited: undefined, - 'self-hosted': undefined, - users: undefined, - unlimited_seats: undefined, - month: undefined, - year: undefined, - wantToPayYearly: undefined, - }, - Encryption: { - createEncryptedSession: undefined, - sessionNotEncrypted: undefined, - sessionEncryptedHaveKeyTooltip: undefined, - sessionEncryptedNoKeyTooltip: undefined, - sessionEncryptedWrongKeyTooltip: undefined, - newEncryptedSessionWarningTitle: undefined, - newEncryptedSessionWarningContent: undefined, - sessionEncryptionError: undefined, - passwordModalTitle: undefined, - passwordModelIncorrect: undefined, - }, - Private: { - lockSuccessNotification: undefined, - unlockSuccessNotification: undefined, - lockButton: undefined, - unlockButton: undefined, - lockDescription: undefined, - cancelButton: undefined, - sessionLockedTitle: undefined, - sessionLockedDescription: undefined, - sessionNonProTitle: undefined, - sessionNonProDescription: undefined, - sessionIsPublic: undefined, - sessionIsPrivate: undefined, - sessionIsPrivateNoAccess: undefined, - }, - TrialPrompt: { - allowanceReachedTitle: undefined, - allowanceReachedDescription: undefined, - nearEndAllowanceTitle: undefined, - nearEndAllowanceDescription: undefined, - onTrialTitle: undefined, - remainingTrialSentence: undefined, - trialEndedTitle: undefined, - trialEndedSentence: undefined, - subscribeNow: undefined, - }, - Chat: { writeAMessage: undefined }, -} as Translation; diff --git a/frontend/src/translations/i18n.ts b/frontend/src/translations/i18n.ts new file mode 100644 index 000000000..bc3f2939b --- /dev/null +++ b/frontend/src/translations/i18n.ts @@ -0,0 +1,32 @@ +import i18n from 'i18next'; +import { initReactI18next } from 'react-i18next'; +import LanguageDetector from 'i18next-browser-languagedetector'; +import resourcesToBackend from 'i18next-resources-to-backend'; +import config from 'utils/getConfig'; + +i18n + .use( + resourcesToBackend((language, _, callback) => { + import(`./locales/${language}.json`) + .then((resources) => { + callback(null, resources); + }) + .catch((error) => { + callback(error, null); + }); + }) + ) + .use(LanguageDetector) + .use(initReactI18next) + .init({ + fallbackLng: config.defaultLanguage, + debug: process.env.NODE_ENV === 'development', + defaultNS: 'ns1', + ns: 'ns1', + + interpolation: { + escapeValue: false, // not needed for react as it escapes by default + }, + }); + +export default i18n; diff --git a/frontend/src/translations/index.ts b/frontend/src/translations/index.ts index 04417ea7d..baa510645 100644 --- a/frontend/src/translations/index.ts +++ b/frontend/src/translations/index.ts @@ -1,7 +1,2 @@ -import useTranslations from './useTranslations'; -export { default as LanguageContext } from './Context'; export { default as languages } from './languages'; export { default as useLanguage } from './useLanguage'; -export * from './types'; - -export default useTranslations; diff --git a/frontend/src/translations/it.ts b/frontend/src/translations/it.ts deleted file mode 100644 index 56a41b326..000000000 --- a/frontend/src/translations/it.ts +++ /dev/null @@ -1,416 +0,0 @@ -import { Translation } from './types'; -import { plural } from './utils'; -export default { - Header: { - subtitle: 'Un buon modo per esprimersi in Agile', - logout: 'Logout', - leave: 'Abbandona', - summaryMode: 'Modalità sommario', - account: undefined, - adminPanel: undefined, - }, - LanguagePicker: { - header: 'Scegli una lingua', - }, - Main: { - hint: 'Puoi invitare altre persone a questa sessione copiando ed incollando la URL', - }, - Home: { - welcome: (userName: string) => `Benvenuto/a, ${userName}`, - }, - PreviousGame: { - createdBy: 'Creato da', - posts: plural('post'), - participants: plural('participante', 'partecipanti'), - votes: plural('voto', 'voti'), - actions: plural('azione', 'azioni'), - }, - Column: { - createGroupTooltip: 'Crea un gruppo per raggruppare i post', - }, - Group: { - emptyGroupTitle: 'Questo gruppo è vuoto', - emptyGroupContent: 'Sposta qui un post per popolare il gruppo', - }, - Post: { - openExtra: 'Features aggiuntive', - closeExtra: 'Chiudi', - vote: 'voto', - votes: 'voti', - deleteButton: 'Cancella', - setActionButton: 'Imposta azione', - setGiphyButton: 'Scegli una immagine Giphy', - noContent: '(Questo post non ha contenuto)', - by: 'da', - upVote: 'mi piace', - downVote: 'non mi piace', - voteRemainingMultiple: (count: number, type: string) => - `Hai ${count} ${type}/i restanti.`, - voteRemainingOne: (type: string) => - `Hai solo un ${type} restante, usalo bene!`, - voteRemainingNone: (type: string) => `Non hai nessun ${type} restante.`, - toggleGiphyButton: 'Toggle immagine Giphy', - }, - Customize: { - title: 'Personalizza il tuo gioco!', - votingCategory: 'Votazione', - votingCategorySub: - 'Imposta tutte le regole relative a "mi piace" e "non mi piace"', - postCategory: 'Impostazioni del Post', - postCategorySub: - "Imposta le azioni che l'utente può fare quando crea o vede un post ", - customTemplateCategory: 'Template di Colonna', - customTemplateCategorySub: - 'Imposta il numero di colonne e le sue caratteristiche', - startButton: 'Fai partire il gioco!', - maxUpVotes: 'Numero massimo di "mi piace"', - maxUpVotesHelp: `Numero massimo di "mi piace" che un utente può mettere`, - maxDownVotes: 'Numero massimo di "non mi piace"', - maxDownVotesHelp: `Numero massimo di "non mi piace" che un utente può mettere`, - maxPosts: undefined, - maxPostsHelp: undefined, - allowSelfVoting: "Permettere l'auto votazione", - allowSelfVotingHelp: - 'Se consentire ad un utente di votare sul proprio post', - allowMultipleVotes: 'Permettere votazioni multiple', - allowMultipleVotesHelp: - 'Se consentire a un utente di votare più volte sullo stesso post', - allowActions: 'Permettere Azioni', - allowActionsHelp: `Se consentire il campo "Azione" (follow-up) su ciascun post`, - allowAuthorVisible: 'Mostra Autore', - allowAuthorVisibleHelp: "Mostra l'autore del post nel post stesso.", - newPostsFirst: undefined, - newPostsFirstHelp: undefined, - allowGiphy: 'Consenti Giphy', - allowGiphyHelp: 'Permetti la creazione di gruppi per raggruppare post', - allowGrouping: 'Consenti il raggruppamento', - allowGroupingHelp: 'Permetti la creazione di gruppi per raggruppare post', - allowReordering: 'Consenti il riordinamento', - allowReorderingHelp: - 'Permetti il riordinamento dei post con il trascinamento', - blurCards: undefined, - blurCardsHelp: undefined, - template: 'Template', - templateHelp: 'Usa un set di colonne predefinito', - numberOfColumns: 'Numbero di colonne', - numberOfColumnsHelp: 'Imposta il numero di colonne', - makeDefaultTemplate: 'Rendi questo template quello di default', - }, - PostBoard: { - customQuestion: 'Colonna personalizzata', - notWellQuestion: 'Cosa potrebbe essere migliorato?', - wellQuestion: 'Cosa è andato bene?', - ideasQuestion: 'Qualche idea brillante da condividere?', - startQuestion: 'Inizia', - editButton: undefined, - stopQuestion: 'Stop', - continueQuestion: 'Continua', - likedQuestion: 'Piaciuto', - lackedQuestion: 'Mancava', - learnedQuestion: 'Imparato', - longedForQuestion: 'Atteso', - anchorQuestion: 'Ancora', - boatQuestion: 'Barca', - islandQuestion: 'Isola', - windQuestion: 'Vento', - rockQuestion: 'Roccia', - disconnected: 'Ti sei disconnesso/a dalla sessione corrente.', - reconnect: 'Riconnesso', - notLoggedIn: - 'Non sei autenticato. Puoi assistere a questa sessione come spettatore ma non puoi partecipare', - maxPostsReached: undefined, - iAmDone: undefined, - iAmNotDoneYet: undefined, - userIsReady: undefined, - }, - GameMenu: { - board: 'Board', - summary: 'Sommario', - }, - Template: { - default: 'Default', - wellNotWell: 'Ok / Non Ok', - startStopContinue: 'Inizia / Stop / Continua', - fourLs: 'Quattro Ls', - sailboat: 'Barca a Vela', - }, - Clients: { - header: 'Partecipanti:', - joined: undefined, - left: undefined, - }, - Join: { - welcome: 'Benvenuto su Retrospected', - standardTab: { - header: 'Crea', - text: 'Clicca qui sotto per iniziare la retrospective', - button: 'Crea una nuova sessione', - customizeButton: 'Personalizza', - }, - optionsTab: { - header: 'Opzioni', - input: 'Nome', - button: 'Crea una sessione personalizzata', - }, - previousTab: { - header: 'Precedente', - rejoinButton: 'Riunisciti', - }, - }, - AnonymousLogin: { - namePlaceholder: - 'Benvenuto! Per favore inserisci il tuo nome per continuare', - buttonLabel: 'Iniziamo', - header: 'Login', - anonymousAuthHeader: 'Login anonimo', - anonymousAuthDescription: - 'Questo creerà un account anonimo, ma non ti permetterà di recuperare le sessioni precedenti.', - authenticatingWith: 'Accedi con', - or: 'oppure', - }, - SocialMediaLogin: { - header: 'Autenticazione con i Social Media', - info: 'Questo utilizzerà il tuo account per autenticarti e ti permetterà di recuperare tutte le tue sessioni. Nessuna password viene memorizzata.', - }, - AuthCommon: { - emailField: undefined, - passwordField: undefined, - nameField: undefined, - passwordScoreWords: undefined, - }, - AccountLogin: { - header: undefined, - loginButton: undefined, - info: undefined, - registerLink: undefined, - forgotPasswordLink: undefined, - errorEmailPasswordIncorrect: undefined, - }, - Register: { - header: undefined, - info: undefined, - registerButton: undefined, - errorAlreadyRegistered: undefined, - errorGeneral: undefined, - messageSuccess: undefined, - errorInvalidEmail: undefined, - }, - ValidateAccount: { - success: undefined, - error: undefined, - loading: undefined, - }, - ResetPassword: { - // Reset Modal - doneMessage: undefined, - header: undefined, - resetButton: undefined, - info: undefined, - // Reset Page - success: undefined, - error: undefined, - loading: undefined, - resetInfo: undefined, - }, - SummaryBoard: { - noPosts: 'Non ci sono post da mostrare', - copyAsMarkdown: 'Copia il sommario come Markdown', - copyAsRichText: 'Copia il sommario come Rich Text', - copySuccessful: 'Hai copiato con successo il testo nella clipboard', - }, - SessionName: { - defaultSessionName: 'La mia Retrospective', - }, - Invite: { - inviteButton: 'Invita', - dialog: { - title: 'Invita persone alla tua retrospective', - text: - 'Per invitare persone alla tua sessione di retrospective, devi solo inviare loro' + - 'la seguente URL', - copyButton: 'Copia la URL nella Clipboard', - }, - }, - Generic: { - ok: 'OK', - cancel: 'Cancella', - }, - Actions: { - tooltip: "Crea un'azione dietro a questo item", - label: "Apri l'Action panel", - summaryTitle: 'Le tue Azioni', - title: 'Azione', - }, - DeleteSession: { - header: undefined, - firstLine: undefined, - secondLine: undefined, - yesImSure: undefined, - cancel: undefined, - }, - RevealCards: { - buttonLabel: undefined, - dialogTitle: undefined, - dialogContent: undefined, - confirmButton: undefined, - cancelButton: undefined, - }, - AccountPage: { - anonymousError: undefined, - details: { - header: undefined, - username: undefined, - email: undefined, - accountType: undefined, - }, - plan: { - header: undefined, - plan: undefined, - youAreOwner: undefined, - youAreMember: undefined, - }, - subscription: { - header: undefined, - manageButton: undefined, - membersEditor: { - title: undefined, - limitReached: undefined, - info: undefined, - }, - }, - trial: { - header: undefined, - yourTrialWillExpireIn: undefined, - subscribe: undefined, - }, - deleteAccount: { - title: undefined, - warning: undefined, - deleteData: undefined, - modal: { - confirm: { - title: undefined, - description: undefined, - confirmation: undefined, - cancellation: undefined, - }, - subheader: undefined, - deleteAccount: undefined, - recommended: undefined, - deleteSessions: { - main: undefined, - selected: undefined, - unselected: undefined, - }, - deletePosts: { - main: undefined, - selected: undefined, - unselected: undefined, - }, - deleteVotes: { - main: undefined, - selected: undefined, - unselected: undefined, - }, - deleteAccountButton: undefined, - cancelButton: undefined, - }, - }, - }, - SubscribePage: { - alertAlreadyPro: undefined, - alertAlreadySubscribed: undefined, - currency: { - title: undefined, - description: undefined, - warning: undefined, - }, - plan: { - title: undefined, - description: undefined, - }, - domain: { - title: undefined, - description: undefined, - invalidDomain: undefined, - }, - subscribe: { - title: undefined, - description: undefined, - cannotRegisterWithAnon: undefined, - checkout: undefined, - }, - }, - SubscribeModal: { - title: undefined, - header: undefined, - description: undefined, - features: { - encryptedSession: { - title: undefined, - description: undefined, - }, - privateSessions: { - title: undefined, - description: undefined, - }, - unlimitedPosts: { - title: undefined, - description: undefined, - }, - }, - subscribeButton: undefined, - payButton: undefined, - cancelButton: undefined, - startTrial: undefined, - }, - Products: { - team: undefined, - unlimited: undefined, - 'self-hosted': undefined, - users: undefined, - unlimited_seats: undefined, - month: undefined, - year: undefined, - wantToPayYearly: undefined, - }, - Encryption: { - createEncryptedSession: undefined, - sessionNotEncrypted: undefined, - sessionEncryptedHaveKeyTooltip: undefined, - sessionEncryptedNoKeyTooltip: undefined, - sessionEncryptedWrongKeyTooltip: undefined, - newEncryptedSessionWarningTitle: undefined, - newEncryptedSessionWarningContent: undefined, - sessionEncryptionError: undefined, - passwordModalTitle: undefined, - passwordModelIncorrect: undefined, - }, - Private: { - lockSuccessNotification: undefined, - unlockSuccessNotification: undefined, - lockButton: undefined, - unlockButton: undefined, - lockDescription: undefined, - cancelButton: undefined, - sessionLockedTitle: undefined, - sessionLockedDescription: undefined, - sessionNonProTitle: undefined, - sessionNonProDescription: undefined, - sessionIsPublic: undefined, - sessionIsPrivate: undefined, - sessionIsPrivateNoAccess: undefined, - }, - TrialPrompt: { - allowanceReachedTitle: undefined, - allowanceReachedDescription: undefined, - nearEndAllowanceTitle: undefined, - nearEndAllowanceDescription: undefined, - onTrialTitle: undefined, - remainingTrialSentence: undefined, - trialEndedTitle: undefined, - trialEndedSentence: undefined, - subscribeNow: undefined, - }, - Chat: { writeAMessage: undefined }, -} as Translation; diff --git a/frontend/src/translations/ja.ts b/frontend/src/translations/ja.ts deleted file mode 100644 index bc567995a..000000000 --- a/frontend/src/translations/ja.ts +++ /dev/null @@ -1,404 +0,0 @@ -import { Translation } from './types'; -export default { - Header: { - subtitle: 'A good way of ranting in an Agile way', - logout: 'ログアウト', - leave: '退室', - summaryMode: '要約モード', - account: undefined, - adminPanel: undefined, - }, - LanguagePicker: { - header: '言語を選択', - }, - Main: { - hint: 'URLを共有すれば新たな参加者を本セッションに招待できます', - }, - Home: { - welcome: undefined, - }, - PreviousGame: { - createdBy: undefined, - posts: undefined, - participants: undefined, - votes: undefined, - actions: undefined, - }, - Column: { - createGroupTooltip: undefined, - }, - Group: { - emptyGroupTitle: '', - emptyGroupContent: '', - }, - Post: { - openExtra: undefined, - closeExtra: undefined, - vote: '投票', - votes: '表決', - deleteButton: '削除', - setActionButton: undefined, - setGiphyButton: undefined, - noContent: '(項目が空です)', - by: undefined, - upVote: undefined, - downVote: undefined, - voteRemainingMultiple: undefined, - voteRemainingOne: undefined, - voteRemainingNone: undefined, - toggleGiphyButton: undefined, - }, - Customize: { - title: undefined, - votingCategory: undefined, - votingCategorySub: undefined, - postCategory: undefined, - postCategorySub: undefined, - customTemplateCategory: undefined, - customTemplateCategorySub: undefined, - startButton: undefined, - editButton: undefined, - maxUpVotes: undefined, - maxUpVotesHelp: undefined, - maxDownVotes: undefined, - maxDownVotesHelp: undefined, - maxPosts: undefined, - maxPostsHelp: undefined, - allowSelfVoting: undefined, - allowSelfVotingHelp: undefined, - allowMultipleVotes: undefined, - allowMultipleVotesHelp: undefined, - allowActions: undefined, - allowActionsHelp: undefined, - allowAuthorVisible: undefined, - allowAuthorVisibleHelp: undefined, - newPostsFirst: undefined, - newPostsFirstHelp: undefined, - allowGiphy: undefined, - allowGiphyHelp: undefined, - allowGrouping: undefined, - allowGroupingHelp: undefined, - allowReordering: undefined, - allowReorderingHelp: undefined, - blurCards: undefined, - blurCardsHelp: undefined, - template: undefined, - templateHelp: undefined, - numberOfColumns: undefined, - numberOfColumnsHelp: undefined, - makeDefaultTemplate: undefined, - }, - PostBoard: { - customQuestion: undefined, - notWellQuestion: '改善できること', - wellQuestion: '良かったこと', - ideasQuestion: '共有したいアイディア', - startQuestion: undefined, - editButton: undefined, - stopQuestion: undefined, - continueQuestion: undefined, - likedQuestion: undefined, - lackedQuestion: undefined, - learnedQuestion: undefined, - longedForQuestion: undefined, - anchorQuestion: undefined, - boatQuestion: undefined, - islandQuestion: undefined, - windQuestion: undefined, - rockQuestion: undefined, - disconnected: undefined, - reconnect: undefined, - notLoggedIn: undefined, - error: undefined, - maxPostsReached: undefined, - iAmDone: undefined, - iAmNotDoneYet: undefined, - userIsReady: undefined, - }, - GameMenu: { - board: undefined, - summary: undefined, - }, - Template: { - default: undefined, - wellNotWell: undefined, - startStopContinue: undefined, - fourLs: undefined, - sailboat: undefined, - }, - Clients: { - header: '現在の参加者', - joined: undefined, - left: undefined, - }, - Join: { - welcome: 'Retrospectedへようこそ', - standardTab: { - header: '作成', - text: 'セッションを作成してレトロスペクティブをはじめる', - button: '新しいセッションを作成する', - customizeButton: undefined, - }, - optionsTab: { - header: '設定', - input: '名前', - button: 'カスタムセッショを作成する', - }, - previousTab: { - header: '以前のセッション', - rejoinButton: '再開', - }, - }, - AnonymousLogin: { - namePlaceholder: '名前を入力', - buttonLabel: 'スタート', - header: 'Login', - anonymousAuthHeader: undefined, - anonymousAuthDescription: undefined, - authenticatingWith: undefined, - or: undefined, - }, - SocialMediaLogin: { - header: undefined, - info: undefined, - }, - AuthCommon: { - emailField: undefined, - passwordField: undefined, - nameField: undefined, - passwordScoreWords: undefined, - }, - AccountLogin: { - header: undefined, - loginButton: undefined, - info: undefined, - registerLink: undefined, - forgotPasswordLink: undefined, - errorEmailPasswordIncorrect: undefined, - }, - Register: { - header: undefined, - info: undefined, - registerButton: undefined, - errorAlreadyRegistered: undefined, - errorGeneral: undefined, - messageSuccess: undefined, - errorInvalidEmail: undefined, - }, - ValidateAccount: { - success: undefined, - error: undefined, - loading: undefined, - }, - ResetPassword: { - // Reset Modal - doneMessage: undefined, - header: undefined, - resetButton: undefined, - info: undefined, - // Reset Page - success: undefined, - error: undefined, - loading: undefined, - resetInfo: undefined, - }, - SummaryBoard: { - noPosts: '表示する項目がありません', - copyAsMarkdown: undefined, - copyAsRichText: undefined, - copySuccessful: undefined, - }, - SessionName: { - defaultSessionName: '新しいレトロスペクティブ', - }, - Invite: { - inviteButton: '招待', - dialog: { - title: 'レトロスペクティブに招待する', - text: '下記のURLを共有して本セッションに招待できます', - copyButton: 'URLをクリップボードにコピー', - }, - }, - Generic: { - ok: 'OK', - cancel: 'キャンセル', - }, - Actions: { - tooltip: 'アクションを作成する', - label: 'アクションパネルを開く', - summaryTitle: 'あなたの行動', - title: 'アクション', - }, - DeleteSession: { - header: undefined, - firstLine: undefined, - secondLine: undefined, - yesImSure: undefined, - cancel: undefined, - }, - RevealCards: { - buttonLabel: undefined, - dialogTitle: undefined, - dialogContent: undefined, - confirmButton: undefined, - cancelButton: undefined, - }, - AccountPage: { - anonymousError: undefined, - details: { - header: undefined, - username: undefined, - email: undefined, - accountType: undefined, - }, - plan: { - header: undefined, - plan: undefined, - youAreOwner: undefined, - youAreMember: undefined, - }, - subscription: { - header: undefined, - manageButton: undefined, - membersEditor: { - title: undefined, - limitReached: undefined, - info: undefined, - }, - }, - trial: { - header: undefined, - yourTrialWillExpireIn: undefined, - subscribe: undefined, - }, - deleteAccount: { - title: undefined, - warning: undefined, - deleteData: undefined, - modal: { - confirm: { - title: undefined, - description: undefined, - confirmation: undefined, - cancellation: undefined, - }, - subheader: undefined, - deleteAccount: undefined, - recommended: undefined, - deleteSessions: { - main: undefined, - selected: undefined, - unselected: undefined, - }, - deletePosts: { - main: undefined, - selected: undefined, - unselected: undefined, - }, - deleteVotes: { - main: undefined, - selected: undefined, - unselected: undefined, - }, - deleteAccountButton: undefined, - cancelButton: undefined, - }, - }, - }, - SubscribePage: { - alertAlreadyPro: undefined, - alertAlreadySubscribed: undefined, - currency: { - title: undefined, - description: undefined, - warning: undefined, - }, - plan: { - title: undefined, - description: undefined, - }, - domain: { - title: undefined, - description: undefined, - invalidDomain: undefined, - }, - subscribe: { - title: undefined, - description: undefined, - cannotRegisterWithAnon: undefined, - checkout: undefined, - }, - }, - SubscribeModal: { - title: undefined, - header: undefined, - description: undefined, - features: { - encryptedSession: { - title: undefined, - description: undefined, - }, - privateSessions: { - title: undefined, - description: undefined, - }, - unlimitedPosts: { - title: undefined, - description: undefined, - }, - }, - subscribeButton: undefined, - payButton: undefined, - cancelButton: undefined, - startTrial: undefined, - }, - Products: { - team: undefined, - unlimited: undefined, - 'self-hosted': undefined, - users: undefined, - unlimited_seats: undefined, - month: undefined, - year: undefined, - wantToPayYearly: undefined, - }, - Encryption: { - createEncryptedSession: undefined, - sessionNotEncrypted: undefined, - sessionEncryptedHaveKeyTooltip: undefined, - sessionEncryptedNoKeyTooltip: undefined, - sessionEncryptedWrongKeyTooltip: undefined, - newEncryptedSessionWarningTitle: undefined, - newEncryptedSessionWarningContent: undefined, - sessionEncryptionError: undefined, - passwordModalTitle: undefined, - passwordModelIncorrect: undefined, - }, - Private: { - lockSuccessNotification: undefined, - unlockSuccessNotification: undefined, - lockButton: undefined, - unlockButton: undefined, - lockDescription: undefined, - cancelButton: undefined, - sessionLockedTitle: undefined, - sessionLockedDescription: undefined, - sessionNonProTitle: undefined, - sessionNonProDescription: undefined, - sessionIsPublic: undefined, - sessionIsPrivate: undefined, - sessionIsPrivateNoAccess: undefined, - }, - TrialPrompt: { - allowanceReachedTitle: undefined, - allowanceReachedDescription: undefined, - nearEndAllowanceTitle: undefined, - nearEndAllowanceDescription: undefined, - onTrialTitle: undefined, - remainingTrialSentence: undefined, - trialEndedTitle: undefined, - trialEndedSentence: undefined, - subscribeNow: undefined, - }, - Chat: { writeAMessage: undefined }, -} as Translation; diff --git a/frontend/src/translations/languages.ts b/frontend/src/translations/languages.ts index 5a8cba500..cf03a0445 100644 --- a/frontend/src/translations/languages.ts +++ b/frontend/src/translations/languages.ts @@ -24,131 +24,141 @@ const pl = () => import('date-fns/locale/pl' /* webpackChunkName: "date-fns-pl" */); const ptBR = () => import('date-fns/locale/pt-BR' /* webpackChunkName: "date-fns-pt-BR" */); -const ru = () => - import('date-fns/locale/ru' /* webpackChunkName: "date-fns-ru" */); +const pt = () => + import('date-fns/locale/pt' /* webpackChunkName: "date-fns-pt" */); +const uk = () => + import('date-fns/locale/uk' /* webpackChunkName: "date-fns-uk" */); const es = () => import('date-fns/locale/es' /* webpackChunkName: "date-fns-es" */); export interface Language { - value: string; iso: string; name: string; englishName: string; dateLocale: () => Promise<{ default: Locale }>; stripeLocale: StripeLocales; + locale: string; } export default [ { - value: 'en', dateLocale: enGB, iso: 'gb', name: 'English', englishName: 'English', stripeLocale: 'en-US', + locale: 'en-GB', }, { - value: 'fr', dateLocale: fr, iso: 'fr', name: 'Français', englishName: 'French', stripeLocale: 'fr-FR', + locale: 'fr-FR', + }, + { + dateLocale: de, + iso: 'de', + name: 'Deutsch', + englishName: 'German', + stripeLocale: 'de-DE', + locale: 'de-DE', + }, + { + dateLocale: es, + iso: 'es', + name: 'Español', + englishName: 'Spanish', + stripeLocale: 'es-ES', + locale: 'es-ES', }, { - value: 'ar', dateLocale: arDZ, iso: 'ae', name: 'عربي', englishName: 'Arabic', stripeLocale: 'ar-AR', + locale: 'ar-SA', }, { - value: 'zhcn', dateLocale: zhCN, iso: 'cn', name: '簡中', englishName: 'Chinese (Simplified)', stripeLocale: 'en-US', + locale: 'zh-CN', }, { - value: 'zhtw', dateLocale: zhTW, iso: 'tw', name: '繁中', englishName: 'Chinese (Traditional)', stripeLocale: 'en-US', + locale: 'zh-TW', }, { - value: 'nl', dateLocale: nl, iso: 'nl', name: 'Nederlands', englishName: 'Dutch', stripeLocale: 'nl-NL', + locale: 'nl-NL', }, { - value: 'de', - dateLocale: de, - iso: 'de', - name: 'Deutsch', - englishName: 'German', - stripeLocale: 'de-DE', - }, - { - value: 'hu', dateLocale: hu, iso: 'hu', name: 'Magyar', englishName: 'Hungarian', stripeLocale: 'en-US', + locale: 'hu-HU', }, { - value: 'it', dateLocale: it, iso: 'it', name: 'Italiano', englishName: 'Italian', stripeLocale: 'it-IT', + locale: 'it-IT', }, { - value: 'ja', dateLocale: ja, iso: 'jp', name: '日本語', englishName: 'Japanese', stripeLocale: 'ja-JP', + locale: 'ja-JP', }, { - value: 'pl', dateLocale: pl, iso: 'pl', name: 'Polski', englishName: 'Polish', stripeLocale: 'en-US', + locale: 'pl-PL', }, { - value: 'ptbr', dateLocale: ptBR, iso: 'br', name: 'Português Brasileiro', englishName: 'Portuguese (Brazilian)', stripeLocale: 'pt-BR', + locale: 'pt-BR', }, { - value: 'ru', - dateLocale: ru, - iso: 'ru', - name: 'Русский', - englishName: 'Russian', - stripeLocale: 'en-US', + dateLocale: pt, + iso: 'pt', + name: 'Português', + englishName: 'Portuguese (Portugal)', + stripeLocale: 'pt-PT', + locale: 'pt-PT', }, { - value: 'es', - dateLocale: es, - iso: 'es', - name: 'Español', - englishName: 'Spanish', - stripeLocale: 'es-ES', + dateLocale: uk, + iso: 'ua', + name: 'Yкраїнський', + englishName: 'Ukrainian', + stripeLocale: 'uk-UA', + locale: 'uk-UA', }, ] as Language[]; diff --git a/frontend/src/translations/locales/ar-SA.json b/frontend/src/translations/locales/ar-SA.json new file mode 100644 index 000000000..8c03cb190 --- /dev/null +++ b/frontend/src/translations/locales/ar-SA.json @@ -0,0 +1,423 @@ +{ + "Header": { + "subtitle": "أسلوب جيّد للتّوبيخ بطريقة مرنة ", + "logout": "خروج", + "leave": "غادر", + "summaryMode": "النّمط الملخّص", + "account": "حسابي", + "adminPanel": "لوحة الإدارة" + }, + "LanguagePicker": { + "header": "إختيار اللُّغة" + }, + "Main": { + "hint": "يمكنُكَ دعوة أشخاص إلى هذه الجلسة عن طريق نسخ عنوان هذه الصفحة" + }, + "Home": { + "welcome": "مرحبا، {{name}}" + }, + "PreviousGame": { + "createdBy": "تم إنشاؤها بواسطة", + "posts_one": "منشور", + "posts_other": "المشاركات", + "participants_one": "مشارك", + "participants_other": "المشاركون", + "votes_one": "التصويت", + "votes_other": "الأصوات", + "actions_one": "اجراء", + "actions_other": "الإجراءات" + }, + "Column": { + "createGroupTooltip": "إنشاء مجموعة لتجميع المشاركات معا" + }, + "Group": { + "emptyGroupTitle": "هذه مجموعة فارغة", + "emptyGroupContent": "نقل منشور هنا لملء هذه المجموعة" + }, + "Post": { + "openExtra": "ميزات إضافية", + "closeExtra": "أغلق", + "vote": "صوت", + "votes": "أصوات", + "deleteButton": "حذف", + "setActionButton": "تعيين الإجراء", + "setGiphyButton": "اختر صورة «غيفي»", + "noContent": "(هذا الموضوع فارغ)", + "by": "بواسطة", + "upVote": "التصويت للأعلى", + "downVote": "التصويت للأسفل", + "voteRemainingMultiple": "لديك {{number}} {{type}}ثانية متبقية.", + "voteRemainingOne": "لديك فقط {{type}} واحد متبقي، جعله عديم!", + "voteRemainingNone": "ليس لديك أي {{type}} متبقي.", + "toggleGiphyButton": "تبديل الصورة الجافية" + }, + "Customize": { + "title": "تخصيص الجلسة الخاصة بك", + "votingCategory": "التصويت", + "votingCategorySub": "تعيين القواعد حول الإعجاب و عدم الإعجاب", + "postCategory": "إعدادات النشر", + "postCategorySub": "تعيين القواعد حول ما يمكن للمستخدم أن يفعله عند إنشاء أو عرض مشاركة", + "customTemplateCategory": "قالب العمود", + "customTemplateCategorySub": "تعيين عدد الأعمدة وخصائصها", + "startButton": "بدء الجلسة", + "editButton": "تحديث", + "maxUpVotes": "الحد الاقصى للتصويتات", + "maxUpVotesHelp": "الحد الأقصى لعدد الأصوات 'الإعجاب' المسموح للمستخدم بالإدلاء بها", + "maxDownVotes": "الحد الاقصى للأصوات", + "maxDownVotesHelp": "الحد الأقصى لعدد الأصوات 'غير المعجبة' المسموح للمستخدم بالإدلاء بها", + "maxPosts": "الحد الأقصى للمشاركات لكل مستخدم", + "maxPostsHelp": "الحد الأقصى لعدد المشاركات التي يمكن للمستخدم إنشاؤها في كل جلسة", + "allowSelfVoting": "السماح بالتصويت الذاتي", + "allowSelfVotingHelp": "ما إذا كان يسمح للمستخدم بالتصويت على مشاركته الخاصة", + "allowMultipleVotes": "السماح بتعدد الأصوات", + "allowMultipleVotesHelp": "ما إذا كان يسمح للمستخدم بالتصويت عدة مرات على نفس المنشور", + "allowActions": "السماح بالإجراءات", + "allowActionsHelp": "ما إذا كان سيتم السماح بحقل \"الإجراء\" (المتابعة) في كل مشاركة", + "allowAuthorVisible": "إظهار المؤلف", + "allowAuthorVisibleHelp": "عرض مؤلف المنشور على المنشور نفسه.", + "newPostsFirst": "إضافة مشاركات جديدة أولاً", + "newPostsFirstHelp": "يتم إضافة مشاركات جديدة في الجزء العلوي من العمود", + "allowGiphy": "السماح بالجفي", + "allowGiphyHelp": "السماح للمستخدمين بتعيين صورة Giphy مقابل مشاركة", + "allowGrouping": "السماح بالتجميع", + "allowGroupingHelp": "السماح بإنشاء مجموعات لتجميع المشاركات معا", + "allowReordering": "السماح بإعادة الطلب", + "allowReorderingHelp": "السماح بإعادة ترتيب المشاركات بسحب وإسقاط", + "blurCards": "طمس البطاقات", + "blurCardsHelp": "محتوى البطاقات غير واضح حتى يكشف المشرف عن المحتوى", + "template": "قالب", + "templateHelp": "استخدام مجموعة محددة مسبقاً من الأعمدة", + "numberOfColumns": "عدد الأعمدة", + "numberOfColumnsHelp": "تعيين عدد الأعمدة", + "makeDefaultTemplate": "اجعل هذا قالبي الافتراضي" + }, + "PostBoard": { + "customQuestion": "عمود مخصص", + "notWellQuestion": "ما الذي يمكن تحسينه ؟", + "wellQuestion": "ما الذي فُعِلَ بنجاح؟", + "ideasQuestion": "هل من أيِّ فكرةٍ ذكيّة ؟", + "startQuestion": "ابدأ", + "stopQuestion": "توقف", + "continueQuestion": "متابعة", + "likedQuestion": "معجب", + "lackedQuestion": "مفقود", + "learnedQuestion": "تعلّم", + "longedForQuestion": "طويل لـ", + "anchorQuestion": "مرساة", + "boatQuestion": "قارب", + "islandQuestion": "الجزيرة", + "windQuestion": "الريح", + "rockQuestion": "الصخور", + "disconnected": "لقد تم فصلك عن الدورة الحالية.", + "reconnect": "إعادة الاتصال", + "notLoggedIn": "لم تقم بتسجيل الدخول. يمكنك عرض هذه الجلسة كمتفرج، ولكن يجب تسجيل الدخول للمشاركة.", + "error_action_unauthorised": "غير مسموح لك بتنفيذ هذا الإجراء.", + "error_cannot_edit_group": "فشل تحرير المجموعة.", + "error_cannot_edit_post": "فشل تحرير المشاركة.", + "error_cannot_get_session": "تعذر الحصول على بيانات الجلسة. الرجاء إعادة تحميل الصفحة.", + "error_cannot_register_vote": "لم يتم تسجيل تصويتك بنجاح.", + "error_cannot_save_group": "لا يمكن حفظ المجموعة التي أنشأتها.", + "error_cannot_save_post": "لا يمكن حفظ المنشور الذي قمت بإنشائه.", + "error_cannot_delete_group": "لا يمكن حذف المجموعة", + "error_cannot_delete_post": "لا يمكن حذف المنشور", + "error_cannot_rename_session": "فشل إعادة تسمية الجلسة", + "error_cannot_save_columns": "فشل حفظ الأعمدة", + "error_cannot_save_options": "فشل حفظ الخيارات", + "maxPostsReached": "لقد وصلت إلى الحد الأقصى لعدد المشاركات التي حددها المشرف", + "iAmDone": "لقد انتهيت!", + "iAmNotDoneYet": "أنا لم أنتهِ بعد...", + "userIsReady": "{{user}} جاهز!" + }, + "GameMenu": { + "board": "المجلس", + "summary": "Summary" + }, + "Template": { + "default": "الافتراضي", + "wellNotWell": "حسنا / غير جيد", + "startStopContinue": "بدء / إيقاف / متابعة", + "fourLs": "أربعة لترات", + "sailboat": "زورق بحري" + }, + "Clients": { + "header": "الضيوف الحاضرين معنا الآن:", + "joined": "انضم {{users}}.", + "left": "بقي {{users}}." + }, + "Join": { + "welcome": " ! مرحبا", + "standardTab": { + "header": "موضوع جديد", + "text": ": انقر أدناه و إبدء إعادة النظر", + "button": "إنشاء جلسة عمل جديدة", + "customizeButton": "تخصيص" + }, + "optionsTab": { + "header": "أكثر", + "input": "عنوان", + "button": "إنشاء جلسة مخصصة" + }, + "previousTab": { + "header": "الجلسات السابقة", + "rejoinButton": "الإنضمام" + } + }, + "AnonymousLogin": { + "namePlaceholder": "من أنت بالضبط؟ أدخل اسمك هنا", + "buttonLabel": "لنبدأ", + "header": "تسجيل الدخول", + "anonymousAuthHeader": "تسجيل دخول مجهول", + "anonymousAuthDescription": "سيؤدي هذا إلى إنشاء حساب مجهول. لن تكون بعض الميزات متاحة.", + "authenticatingWith": "المصادقة مع", + "or": "أو" + }, + "SocialMediaLogin": { + "header": "OAuth", + "info": "هذا سوف يستخدم موفر طرف ثالث من اختيارك للمصادقة عليك. لا يتم تخزين كلمة المرور." + }, + "AuthCommon": { + "emailField": "البريد الإلكتروني", + "passwordField": "كلمة المرور", + "nameField": "اسمك (لأغراض العرض)", + "passwordScoreWords": [ + "ضعيف", + "ضعيف", + "ليس تماما", + "جيد", + "قوي" + ] + }, + "AccountLogin": { + "header": "كلمة المرور", + "loginButton": "تسجيل الدخول", + "info": "تسجيل الدخول باستخدام بريدك الإلكتروني وكلمة المرور الخاصة بك.", + "registerLink": "غير مسجل؟ انقر هنا", + "forgotPasswordLink": "هل نسيت كلمة المرور؟", + "errorEmailPasswordIncorrect": "بيانات الاعتماد الخاصة بك غير صحيحة." + }, + "Register": { + "header": "تسجيل", + "info": "احصل على حساب تراجعي!", + "registerButton": "تسجيل", + "errorAlreadyRegistered": "هذا البريد الإلكتروني مسجل بالفعل", + "errorGeneral": "حدث خطأ أثناء محاولة إنشاء حسابك.", + "messageSuccess": "شكرًا لك! يجب أن تتلقى رسالة بريد إلكتروني قريبًا للتحقق من صحة حسابك.", + "errorInvalidEmail": "الرجاء إدخال بريد إلكتروني صالح" + }, + "ValidateAccount": { + "success": "تم التحقق من بريدك الإلكتروني بشكل صحيح. سأقوم بتسجيل دخولك في لحظة!", + "error": "حدث خطأ أثناء التحقق من صحة بريدك الإلكتروني.", + "loading": "نحن نقوم بالتحقق من صحة بريدك الإلكتروني. الرجاء الانتظار." + }, + "ResetPassword": { + "doneMessage": "تم! ألقي نظرة على رسائل البريد الإلكتروني الخاصة بك، يجب أن تحصل على رابط لإعادة تعيين كلمة المرور الخاصة بك.", + "header": "إعادة تعيين كلمة المرور", + "resetButton": "إعادة تعيين كلمة المرور", + "info": "هل نسيت كلمة المرور؟ ليس هناك مشكلة. أدخل بريدك الإلكتروني أدناه وستحصل على طلب إعادة تعيين البريد الإلكتروني.", + "success": "تم تحديث كلمة المرور الخاصة بك. سأقوم بتسجيل الدخول في ثانية!", + "error": "حدث خطأ أثناء تحديث كلمة المرور الخاصة بك.", + "loading": "نحن نقوم بتحديث كلمة المرور الخاصة بك. الرجاء الانتظار.", + "resetInfo": "الرجاء تقديم كلمة مرور جديدة" + }, + "SummaryBoard": { + "noPosts": "لا توجد مشاركات للعرض", + "copyAsMarkdown": "نسخ الملخص كـ Markdown", + "copyAsRichText": "نسخ الملخص في النص الغني", + "copySuccessful": "تم نسخ ملخصك بنجاح في الحافظة الخاصة بك" + }, + "SessionName": { + "defaultSessionName": "جلسة جديدة" + }, + "Invite": { + "inviteButton": "دعوة", + "dialog": { + "title": "دعوة أشخاص إلى الجلسة", + "text": "لدعوة أشخاص إلى الجلسة يمكنك إرسال عنوان هذه الصفحة", + "copyButton": "نسخ العنوان" + } + }, + "Generic": { + "ok": "حسناً", + "cancel": "إلغاء" + }, + "Actions": { + "tooltip": "إنشاء إجراء على ظهر هذا العنصر", + "label": "افتح لوحة Action", + "summaryTitle": "أفعالك", + "title": "عمل" + }, + "DeleteSession": { + "header": "حذف '{{name}}'؟", + "firstLine": "حذف جلسة أمر لا رجعة فيه. سيؤدي إلى حذف جميع المشاركات، والتصويبات، والمجموعات، والجلسة نفسها. لا يمكن استعادة البيانات.", + "secondLine": "هل أنت متأكد من أنك تريد حذف هذه الجلسة وكل محتوياتها؟", + "yesImSure": "نعم، أنا متأكد", + "cancel": "لا، أنا آسف، لقد ارتكبت خطأ" + }, + "RevealCards": { + "buttonLabel": "كشف", + "dialogTitle": "كشف جميع البطاقات", + "dialogContent": "هذا سوف يكشف جميع البطاقات غير المرغوب فيها للجميع. لا يمكن التراجع عن ذلك.", + "confirmButton": "هيا بنا نكشف", + "cancelButton": "لا شكراً" + }, + "AccountPage": { + "anonymousError": "الحسابات المجهولة المصدر لا يمكن الوصول إلى ملفها الشخصي (لأنها لا تملك ملفاً).", + "details": { + "header": "التفاصيل الخاصة بك", + "username": "اسم المستخدم", + "email": "البريد الإلكتروني", + "accountType": "نوع الحساب" + }, + "plan": { + "header": "خطتك", + "plan": "خطة", + "youAreOwner": "أنت صاحب هذه الخطة، من خلال الاشتراك أدناه.", + "youAreMember": "أنت على هذه الخطة من خلال اشتراك شخص آخر." + }, + "subscription": { + "header": "اشتراكك", + "manageButton": "إدارة اشتراكي", + "membersEditor": { + "title": "فريقك", + "limitReached": "لقد وصلت إلى الحد الأقصى للاشتراك الخاص بك (المستخدمون{{limit}} ، بما في ذلك نفسك). الرجاء إزالة الأعضاء، أو الترقية إلى حساب شركة غير محدود.", + "info": "إضافة رسائل البريد الإلكتروني أدناه لمنح حسابات Pro حتى {{limit}} من الزملاء الآخرين. اضغط Enter بعد كل عنوان بريد إلكتروني." + } + }, + "trial": { + "header": "تجريبك التجريبي", + "yourTrialWillExpireIn": "ستنتهي التجربة الخاصة بك في {{date}}.", + "subscribe": "اشترك الآن" + }, + "deleteAccount": { + "title": "GDPR", + "warning": "لديك الحق في أن تنسى. مع ذلك، كن حذراً عند حذف حسابك. لا يمكن التراجع عن ذلك.", + "deleteData": "حذف بياناتي", + "modal": { + "confirm": { + "title": "هل أنت متأكد تماماً؟", + "description": "ولا يوجد تراجع في هذا الشأن.", + "confirmation": "نعم أريد حذف جميع بياناتي", + "cancellation": "اخرجي من هنا" + }, + "subheader": "اختر ما تريد حذفه", + "deleteAccount": "حذف حسابك وأي هويات مرتبطة ببريدك الإلكتروني.", + "recommended": "موصى", + "deleteSessions": { + "main": "هل يجب علينا حذف الجلسات (رجعية) التي أنشأتها؟", + "selected": "سيتم حذف جلساتكم وجميع بياناتهم، بما في ذلك مناصب الآخرين والتصويت، بشكل دائم.", + "unselected": "سيتم الحفاظ على جلساتك وسيصبح مؤلفها مستخدما مجهولا." + }, + "deletePosts": { + "main": "هل يجب علينا حذف جميع المشاركات التي كتبتها؟", + "selected": "سيتم حذف منشوراتك في أي جلسة والتصويبات والإجراءات المرتبطة بها بشكل دائم.", + "unselected": "سيتم الاحتفاظ بمشاركاتك، ولكن ستصبح مرتبطة مع مستخدم مجهول." + }, + "deleteVotes": { + "main": "هل ينبغي لنا أيضا حذف جميع تصويتاتك؟", + "selected": "سيتم حذف تصويتك في جميع الجلسات بشكل دائم.", + "unselected": "سيتم الاحتفاظ بأصواتك، ولكن ستصبح مرتبطة مع مستخدم مجهول." + }, + "deleteAccountButton": "حذف حسابك", + "cancelButton": "إلغاء" + } + } + }, + "SubscribePage": { + "alertAlreadyPro": "أنت بالفعل مستخدم محترف، لذلك قد لا تحتاج إلى اشتراك آخر.", + "alertAlreadySubscribed": "لديك بالفعل اشتراك، لذلك قد لا تحتاج إلى اشتراك آخر.", + "currency": { + "title": "العملة", + "description": "اختر عملة ترغب في الحصول على فاتورة بها", + "warning": "تم تعيين حسابك بالفعل لاستخدام {{currency}}، لذلك لا يمكنك تغيير العملة بعد الآن." + }, + "plan": { + "title": "خطة", + "description": "اختر الخطة التي تناسب حالة الاستخدام الخاصة بك!" + }, + "domain": { + "title": "النطاق", + "description": "ينطبق اشتراكك غير المحدود على نطاق معين. أي مستخدم لديه نطاق البريد الإلكتروني هذا سيصبح تلقائياً مستخدماً محترفاً.", + "invalidDomain": "الرجاء توفير نطاق صالح. النطاق لا يمكن أن يكون مجاناً أو قابلاً للاستعمال في البريد الإلكتروني." + }, + "subscribe": { + "title": "الدفع", + "description": "سيتم توجيهك إلى شريكنا، الشريط، للدفع", + "cannotRegisterWithAnon": "تحتاج إلى تسجيل الدخول باستخدام حساب OAuth أو كلمة المرور للمتابعة.", + "checkout": "الدفع" + } + }, + "SubscribeModal": { + "title": "الاشتراك المحترف", + "header": "نسخة محترفة تراجعية", + "description": "قم بحماية بيانات شركتك عن طريق الاشتراك في Retrospected Pro. مع Rerspected Pro، احصل على الميزات التالية وأكثر منها:", + "features": { + "encryptedSession": { + "title": "الجلسات المشفرة", + "description": "البيانات الخاصة بك مشفرة في المتصفح الخاص بك، مما يجعل من المستحيل فك التشفير على خادم Respected" + }, + "privateSessions": { + "title": "الجلسات الخاصة", + "description": "تأكد من أن الأشخاص المصرح لهم فقط يمكنهم الوصول إلى جلستك." + }, + "unlimitedPosts": { + "title": "مشاركات غير محدودة", + "description": "مع اشتراك محترف، احصل على مشاركات غير محدودة." + } + }, + "subscribeButton": "اشترك", + "payButton": "حدد", + "cancelButton": "إلغاء", + "startTrial": "30 يوم تجريبي" + }, + "Products": { + "team": "ممتاز لفرق أصغر، يمكنك اختيار ما يصل إلى 20 زميلاً سيتم ترقيتهم إلى حساب محترف.", + "unlimited": "إذا كنت شركة أكبر، فستستمتع بعدد غير محدود من حسابات المحترفين.", + "self-hosted": "تم التنقيب عنها في المباني، رسوم لمرة واحدة، وتحديثات غير محدودة. حافظ على السيطرة الكاملة على بياناتك إلى الأبد.", + "users": "{{users}} مستخدمين", + "unlimited_seats": "غير محدود", + "month": "شهر", + "year": "سنة", + "wantToPayYearly": "أريد أن أدفع سنويا (كل 12 شهرا)، واحصل على شهر واحد مجانا في السنة!" + }, + "Encryption": { + "createEncryptedSession": "جلسة مشفرة", + "sessionNotEncrypted": "هذه الجلسة غير مشفرة.", + "sessionEncryptedHaveKeyTooltip": "هذه الجلسة مشفرة، والمفتاح مخزون في المتصفح الخاص بك. يمكنك فتح هذه الجلسة دون الحاجة إلى توفير كلمة المرور مرة أخرى.", + "sessionEncryptedNoKeyTooltip": "هذه الجلسة مشفرة، والمفتاح غير مخزن في المتصفح الخاص بك. سوف يطلب منك مفتاح فك التشفير عند افتتاح هذه الجلسة.", + "sessionEncryptedWrongKeyTooltip": "هذه الجلسة مشفرة، والمفتاح الذي قمت بتخزينه ليس هو المفتاح الصحيح.", + "newEncryptedSessionWarningTitle": "هذه الجلسة مشفرة محليا", + "newEncryptedSessionWarningContent": "من المهم جداً أن تحفظ عنوان URL الكامل (الذي يحتوي على المفتاح) في مكان ما آمن، أو على الأقل مفتاح التشفير: {{key}}. إذا فقدت مفتاح التشفير هذا، لا يوجد شيء يمكن فعله لاسترداد البيانات.", + "sessionEncryptionError": "هذه الجلسة مشفرة، ولا يبدو أن لديك مفتاح فك التشفير مخزون محليا. الرجاء استخدام الرابط الأصلي، بما في ذلك مفتاح فك التشفير.", + "passwordModalTitle": "الجلسة المشفرة - أدخل كلمة المرور", + "passwordModelIncorrect": "مفتاح التشفير غير صحيح." + }, + "Private": { + "lockSuccessNotification": "تم جعل جلستك خاصة بنجاح. لا يمكن لأي مشاركين جدد الانضمام إليها.", + "unlockSuccessNotification": "تم إعلان جلسة العمل الخاصة بك بنجاح. يمكن لأي شخص أن ينضم.", + "lockButton": "جعلها خاصة", + "unlockButton": "جعل الجمهور", + "lockDescription": "أنت على وشك جعل الجلسة خاصة. سيسمح فقط للمشاركين الحاليين (المدرجة أدناه) بالدخول إلى هذه الجلسة بمجرد قفلهم.", + "cancelButton": "إلغاء", + "sessionLockedTitle": "هذه الجلسة سرية.", + "sessionLockedDescription": "من فضلك اطلب من المشرف فتح القفل حتى تتمكن من الانضمام. ثم قم بتحديث هذه الصفحة.", + "sessionNonProTitle": "هذه الجلسة متاحة فقط للمستخدمين المحترفين", + "sessionNonProDescription": "هذه الجلسة تستخدم الميزات المتاحة فقط للمستخدمين المحترفين. الرجاء الطلب من المشرف أو صاحب الاشتراك أن يعطيك حساب محترف.", + "sessionIsPublic": "وهذه الجلسة علنية ويمكن لأي شخص الوصول إليها.", + "sessionIsPrivate": "هذه الجلسة خاصة، ولديك حق الوصول.", + "sessionIsPrivateNoAccess": "هذه الجلسة خاصة، ولكن ليس لديك حق الوصول." + }, + "TrialPrompt": { + "allowanceReachedTitle": "لقد وصلت إلى نقودك المجانية", + "allowanceReachedDescription": "للحصول على مشاركات غير محدودة، يرجى الاشتراك في Respected Pro", + "nearEndAllowanceTitle": "أنت تقترب من نهاية حصتك", + "nearEndAllowanceDescription": "لديك حوالي {{quota}} مشاركات متبقية", + "onTrialTitle": "تم التنقيب عن المحترف - تجريبي", + "remainingTrialSentence": "بقي لديك {{remaining}} في تجربتك.", + "trialEndedTitle": "انتهت تجربتك المحترفة المعاد النظر فيها", + "trialEndedSentence": "اشترك اليوم لاستعادة الوصول إلى ميزات المحترف.", + "subscribeNow": "اشترك الآن!" + }, + "Chat": { + "writeAMessage": "اكتب رسالة هنا..." + } +} \ No newline at end of file diff --git a/frontend/src/translations/locales/de-DE.json b/frontend/src/translations/locales/de-DE.json new file mode 100644 index 000000000..8cffb89c7 --- /dev/null +++ b/frontend/src/translations/locales/de-DE.json @@ -0,0 +1,423 @@ +{ + "Header": { + "subtitle": "Ein schöner Weg auf eine agile Art zu meckern", + "logout": "Abmelden", + "leave": "Verlassen", + "summaryMode": "Zusammenfassungsmodus", + "account": "Mein Konto", + "adminPanel": "Administrationsbereich" + }, + "LanguagePicker": { + "header": "Sprache auswählen" + }, + "Main": { + "hint": "Du kannst Andere zu dieser Session einladen indem Du ihnen die URL schickst" + }, + "Home": { + "welcome": "Willkommen, {{name}}" + }, + "PreviousGame": { + "createdBy": "Erstellt von", + "posts_one": "eintragen", + "posts_other": "posten", + "participants_one": "teilnehmer", + "participants_other": "teilnehmer", + "votes_one": "abstimmen", + "votes_other": "stimmen", + "actions_one": "aktion", + "actions_other": "aktionen" + }, + "Column": { + "createGroupTooltip": "Erstelle eine Gruppe um Beiträge zusammen zu gruppieren" + }, + "Group": { + "emptyGroupTitle": "Dies ist eine leere Gruppe", + "emptyGroupContent": "Einen Beitrag hierher verschieben, um diese Gruppe zu füllen" + }, + "Post": { + "openExtra": "Zusätzliche Funktionen", + "closeExtra": "Schließen", + "vote": "Stimme", + "votes": "Stimmen", + "deleteButton": "Löschen", + "setActionButton": "Aktion setzen", + "setGiphyButton": "Giphy-Bild auswählen", + "noContent": "(Dieser Post hat keinen Inhalt)", + "by": "von", + "upVote": "positiv abstimmen", + "downVote": "abstimmend", + "voteRemainingMultiple": "Du hast noch {{number}} {{type}}s übrig.", + "voteRemainingOne": "Du hast nur noch ein {{type}} übrig, mach es zählen!", + "voteRemainingNone": "Sie haben keine {{type}} übrig.", + "toggleGiphyButton": "Giphy-Bild umschalten" + }, + "Customize": { + "title": "Personalisiere Dein Spiel", + "votingCategory": "Abstimmung", + "votingCategorySub": "Setze die Abstimmregeln", + "postCategory": "Beitragseinstellungen", + "postCategorySub": "Stelle ein, wie Nutzer mit Beitragen interagieren können", + "customTemplateCategory": "Spaltenkonfiguration", + "customTemplateCategorySub": "Setze die Anzahl an Spalten und deren Eigenschaften", + "startButton": "Spiel starten!", + "editButton": "Aktualisieren", + "maxUpVotes": "Max. Up-Bewertungen", + "maxUpVotesHelp": "Maximale Anzahl an 'up-votes', die ein Nutzer geben kann", + "maxDownVotes": "Max. Abwärtsstimmen", + "maxDownVotesHelp": "Maximale Anzahl an 'down-votes', die ein Nutzer geben kann", + "maxPosts": "Max. Beiträge pro Benutzer", + "maxPostsHelp": "Maximale Anzahl von Beiträgen, die ein Benutzer pro Sitzung erstellen kann", + "allowSelfVoting": "Eigene Posts bewerten", + "allowSelfVotingHelp": "Soll es Nutzern möglich sein eigene Beiträge zu bewerten?", + "allowMultipleVotes": "Mehrfachabstimmung", + "allowMultipleVotesHelp": "Soll es Nutzern möglich sein mehrfach zu bewerten?", + "allowActions": "Erlaube Maßnahmen", + "allowActionsHelp": "Bestimmt ob Maßnahmen hinzugefügt werden können", + "allowAuthorVisible": "Zeige Author", + "allowAuthorVisibleHelp": "Zeigt den Author eines Posts an.", + "newPostsFirst": "Neue Beiträge zuerst hinzufügen", + "newPostsFirstHelp": "Neue Beiträge werden oben in der Spalte hinzugefügt", + "allowGiphy": "Giphy erlauben", + "allowGiphyHelp": "Benutzern erlauben, ein Giphy-Bild gegen einen Beitrag zu setzen", + "allowGrouping": "Gruppieren erlauben", + "allowGroupingHelp": "Erstelle Gruppen, um Beiträge zusammenzufassen", + "allowReordering": "Nachbestellung erlauben", + "allowReorderingHelp": "Erlaubt die Nachbestellung von Posts per Drag-and-Drop", + "blurCards": "Unschärfe Karten", + "blurCardsHelp": "Karteninhalte werden verschwommen, bis der Moderator den Inhalt aufdeckt", + "template": "Vorlage", + "templateHelp": "Nutze ein vordefiniertes Spaltenset", + "numberOfColumns": "Anzahl an Spalten", + "numberOfColumnsHelp": "Setze die Anzahl an Spalten", + "makeDefaultTemplate": "Diese Standardvorlage erstellen" + }, + "PostBoard": { + "customQuestion": "Eigene Spalte", + "notWellQuestion": "Was können wir verbessern?", + "wellQuestion": "Was lief gut?", + "ideasQuestion": "Geniale Einfälle?", + "startQuestion": "Start", + "stopQuestion": "Stoppen", + "continueQuestion": "Weiter", + "likedQuestion": "Gefällt", + "lackedQuestion": "Fehlt", + "learnedQuestion": "Gelernt", + "longedForQuestion": "Gesehen nach", + "anchorQuestion": "Anker", + "boatQuestion": "Boot", + "islandQuestion": "Insel", + "windQuestion": "Wind", + "rockQuestion": "Fels", + "disconnected": "Sie wurden von der aktuellen Sitzung getrennt.", + "reconnect": "Neu verbinden", + "notLoggedIn": "Sie sind nicht eingeloggt. Sie können diese Sitzung als Zuschauer betrachten, müssen sich aber einloggen, um daran teilzunehmen.", + "error_action_unauthorised": "Sie sind nicht berechtigt, diese Aktion auszuführen.", + "error_cannot_edit_group": "Bearbeiten der Gruppe fehlgeschlagen.", + "error_cannot_edit_post": "Bearbeiten des Beitrags fehlgeschlagen.", + "error_cannot_get_session": "Die Sitzungsdaten konnten nicht abgerufen werden. Bitte laden Sie die Seite neu.", + "error_cannot_register_vote": "Deine Stimme wurde nicht erfolgreich registriert.", + "error_cannot_save_group": "Die von Ihnen erstellte Gruppe konnte nicht gespeichert werden.", + "error_cannot_save_post": "Der Beitrag, den Sie erstellt haben, konnte nicht gespeichert werden.", + "error_cannot_delete_group": "Die Gruppe konnte nicht gelöscht werden", + "error_cannot_delete_post": "Der Beitrag konnte nicht gelöscht werden", + "error_cannot_rename_session": "Umbenennen der Sitzung fehlgeschlagen", + "error_cannot_save_columns": "Spalten speichern fehlgeschlagen", + "error_cannot_save_options": "Speichern der Optionen fehlgeschlagen", + "maxPostsReached": "Sie haben die vom Moderator festgelegte maximale Anzahl von Beiträgen erreicht.", + "iAmDone": "Ich bin fertig!", + "iAmNotDoneYet": "Ich bin noch nicht fertig...", + "userIsReady": "{{user}} ist bereit!" + }, + "GameMenu": { + "board": "Brett", + "summary": "Summary" + }, + "Template": { + "default": "Standard", + "wellNotWell": "Gut / Nicht Gut", + "startStopContinue": "Start / Stop / Weiter", + "fourLs": "Vier Ls", + "sailboat": "Segelboot" + }, + "Clients": { + "header": "Mit dabei sind:", + "joined": "{{users}} beigetreten.", + "left": "{{users}} ist übrig." + }, + "Join": { + "welcome": "Willkommen zu Retrospected", + "standardTab": { + "header": "Erstellen", + "text": "Klicke unten und starte deine Retrospektive:", + "button": "Erstelle eine neue Session", + "customizeButton": "Personalisieren" + }, + "optionsTab": { + "header": "Optionen", + "input": "Name", + "button": "Erstelle eine personalisierte Session" + }, + "previousTab": { + "header": "Letzte", + "rejoinButton": "Erneut beitreten" + } + }, + "AnonymousLogin": { + "namePlaceholder": "Wer genau bist Du? Gib hier Deinen Namen ein", + "buttonLabel": "Auf gehts!", + "header": "Anmelden", + "anonymousAuthHeader": "Anonymer Login", + "anonymousAuthDescription": "Dies wird einen anonymen Account erstellen. Einige Funktionen sind nicht verfügbar.", + "authenticatingWith": "Authentifizierung mit", + "or": "oder" + }, + "SocialMediaLogin": { + "header": "OAuh", + "info": "Dies wird einen Drittanbieter Ihrer Wahl verwenden, um Sie zu authentifizieren. Es wird kein Passwort gespeichert." + }, + "AuthCommon": { + "emailField": "E-Mail", + "passwordField": "Passwort", + "nameField": "Ihr Name (für Anzeigezwecke)", + "passwordScoreWords": [ + "schwach", + "schwach", + "nicht ganz", + "gut", + "stark" + ] + }, + "AccountLogin": { + "header": "Passwort", + "loginButton": "Anmelden", + "info": "Melden Sie sich mit Ihrer E-Mail und Ihrem Passwort an.", + "registerLink": "Nicht registriert? Klicken Sie hier", + "forgotPasswordLink": "Passwort vergessen?", + "errorEmailPasswordIncorrect": "Ihre Zugangsdaten sind falsch." + }, + "Register": { + "header": "Registrieren", + "info": "Holen Sie sich ein Retrospected Account!", + "registerButton": "Registrieren", + "errorAlreadyRegistered": "Diese E-Mail ist bereits registriert", + "errorGeneral": "Beim Versuch, Ihr Konto zu erstellen, ist ein Fehler aufgetreten.", + "messageSuccess": "Vielen Dank! Sie sollten in Kürze eine E-Mail erhalten, um Ihr Konto zu bestätigen.", + "errorInvalidEmail": "Bitte geben Sie eine gültige E-Mail ein" + }, + "ValidateAccount": { + "success": "Deine E-Mail wurde korrekt überprüft. Ich werde dich in einer Sekunde einloggen!", + "error": "Beim Überprüfen Ihrer E-Mail ist ein Fehler aufgetreten.", + "loading": "Wir validieren Ihre E-Mail. Bitte warten." + }, + "ResetPassword": { + "doneMessage": "Fertig! Schau dir deine E-Mails an, du solltest einen Link zum Zurücksetzen deines Passworts erhalten.", + "header": "Passwort zurücksetzen", + "resetButton": "Passwort zurücksetzen", + "info": "Passwort vergessen? Kein Problem. Geben Sie Ihre E-Mail unten ein und Sie erhalten eine Rücksetz-E-Mail-Eingabe.", + "success": "Dein Passwort wurde aktualisiert. Ich werde dich in einer Sekunde einloggen!", + "error": "Beim Aktualisieren Ihres Passworts ist ein Fehler aufgetreten.", + "loading": "Wir aktualisieren Ihr Passwort. Bitte warten.", + "resetInfo": "Bitte geben Sie ein neues Passwort ein" + }, + "SummaryBoard": { + "noPosts": "Es gibt keine Beiträge", + "copyAsMarkdown": "Zusammenfassung als Markdown kopieren", + "copyAsRichText": "Zusammenfassung als Rich Text kopieren", + "copySuccessful": "Sie haben Ihre Zusammenfassung erfolgreich in Ihre Zwischenablage kopiert" + }, + "SessionName": { + "defaultSessionName": "Meine Retrospektive" + }, + "Invite": { + "inviteButton": "Einladen", + "dialog": { + "title": "Lade Andere in deine Retrospektive ein", + "text": "Um Andere in deine Retrospektive einzuladen schicke ihnen einfach die folgende URL", + "copyButton": "URL in die Zwischenablage kopieren" + } + }, + "Generic": { + "ok": "Ok", + "cancel": "Abbrechen" + }, + "Actions": { + "tooltip": "Erstelle hierzu eine Maßnahme", + "label": "Öffne das Aktionspanel", + "summaryTitle": "Deine Maßnahmen", + "title": "Maßnahme" + }, + "DeleteSession": { + "header": "'{{name}}'?", + "firstLine": "Das Löschen einer Sitzung ist unumkehrbar. Es werden alle Beiträge, Abstimmungen, Gruppen und die Sitzung selbst gelöscht. Die Daten können nicht wiederhergestellt werden.", + "secondLine": "Sind Sie sicher, dass Sie diese Sitzung und ihren gesamten Inhalt löschen möchten?", + "yesImSure": "Ja, ich bin sicher", + "cancel": "Nein, es tut mir leid, ich habe einen Fehler gemacht" + }, + "RevealCards": { + "buttonLabel": "Offenlegen", + "dialogTitle": "Alle Karten anzeigen", + "dialogContent": "Dies zeigt alle verschwommenen Karten für alle auf. Dies kann nicht rückgängig gemacht werden.", + "confirmButton": "Lass uns enthüllen!", + "cancelButton": "Nein danke" + }, + "AccountPage": { + "anonymousError": "Anonyme Konten können keinen Zugriff auf ihr Profil haben (weil sie kein Profil haben).", + "details": { + "header": "Ihre Details", + "username": "Benutzername", + "email": "E-Mail", + "accountType": "Kontotyp" + }, + "plan": { + "header": "Ihr Plan", + "plan": "Plan", + "youAreOwner": "Sie sind der Besitzer dieses Pakets, durch das untenstehende Abonnement.", + "youAreMember": "Du bist auf diesem Plan durch ein anderes Abonnement." + }, + "subscription": { + "header": "Ihr Abonnement", + "manageButton": "Mein Abonnement verwalten", + "membersEditor": { + "title": "Ihr Team", + "limitReached": "Sie haben das Limit Ihres Abonnements erreicht ({{limit}} Benutzer, einschließlich sich selbst). Bitte entfernen Sie Mitglieder, oder upgraden Sie auf ein unbegrenztes Firmenkonto.", + "info": "Fügen Sie unten E-Mails hinzu, um bis zu {{limit}} anderen Kollegen Konten zu gewähren. Drücken Sie Enter nach jeder E-Mail-Adresse." + } + }, + "trial": { + "header": "Ihre Testversion", + "yourTrialWillExpireIn": "Ihre Testversion endet in {{date}}.", + "subscribe": "Jetzt abonnieren" + }, + "deleteAccount": { + "title": "DDR", + "warning": "Sie haben das Recht, vergessen zu werden. Seien Sie vorsichtig, wenn Sie Ihr Konto löschen. Dies kann nicht rückgängig gemacht werden.", + "deleteData": "Meine Daten löschen", + "modal": { + "confirm": { + "title": "Sind Sie absolut sicher?", + "description": "Hier gibt es keinen Rückschritt.", + "confirmation": "Ja, ich möchte alle meine Daten löschen", + "cancellation": "Hol mich hier aus" + }, + "subheader": "Wähle was löschen soll", + "deleteAccount": "Löschen Sie Ihr Konto und alle Identitäten, die mit Ihrer E-Mail verknüpft sind.", + "recommended": "Empfohlen", + "deleteSessions": { + "main": "Sollen wir die von Ihnen erstellten Sitzungen (Retrospektiven) löschen?", + "selected": "Ihre Sitzungen und alle ihre Daten, einschließlich der Beiträge und Abstimmungen anderer Personen, werden dauerhaft gelöscht.", + "unselected": "Ihre Sitzungen werden gespeichert und der Autor wird ein anonymer Benutzer." + }, + "deletePosts": { + "main": "Sollen wir alle Beiträge löschen, die du geschrieben hast?", + "selected": "Ihre Beiträge in jeder Sitzung und ihre zugehörigen Stimmen und Aktionen werden dauerhaft gelöscht.", + "unselected": "Ihre Beiträge werden aufbewahrt, aber sie werden mit einem anonymen Benutzer verknüpft." + }, + "deleteVotes": { + "main": "Sollen wir auch alle Ihre Abstimmungen löschen?", + "selected": "Ihre Stimmen in allen Sitzungen werden dauerhaft gelöscht.", + "unselected": "Deine Stimmen werden beibehalten, aber sie werden mit einem anonymen Benutzer assoziiert." + }, + "deleteAccountButton": "IHRE KONTO LÖSCHEN", + "cancelButton": "Abbrechen" + } + } + }, + "SubscribePage": { + "alertAlreadyPro": "Du bist bereits ein Pro-Nutzer, also benötigst du kein weiteres Abonnement.", + "alertAlreadySubscribed": "Du hast bereits ein Abonnement, daher brauchst du kein anderes Abonnement.", + "currency": { + "title": "Währung", + "description": "Wählen Sie eine Währung aus, mit der Sie abgerechnet werden möchten", + "warning": "Ihr Konto ist bereits auf {{currency}}gesetzt, so dass Sie die Währung nicht mehr ändern können." + }, + "plan": { + "title": "Plan", + "description": "Wählen Sie den Plan, der zu Ihrem Einsatzfall passt!" + }, + "domain": { + "title": "Domäne", + "description": "Ihr unbegrenztes Abonnement gilt für eine bestimmte Domain. Jeder Benutzer mit dieser E-Mail-Domain wird automatisch ein Pro-Benutzer.", + "invalidDomain": "Bitte geben Sie eine gültige Domain an. Die Domain kann keine kostenlose oder verfügbare E-Mail-Domain sein." + }, + "subscribe": { + "title": "Kasse", + "description": "Sie werden zu unserem Partner Stripe, zur Zahlung weitergeleitet", + "cannotRegisterWithAnon": "Sie müssen mit einem OAuth oder Passwort angemeldet sein, um fortzufahren.", + "checkout": "Kasse" + } + }, + "SubscribeModal": { + "title": "Pro Abonnement", + "header": "Retrospected Pro", + "description": "Schützen Sie Ihre Unternehmensdaten, indem Sie Retrospected Pro abonnieren. Mit Retrospected Pro erhalten Sie folgende Funktionen und mehr:", + "features": { + "encryptedSession": { + "title": "Verschlüsselte Sitzungen", + "description": "Ihre Daten werden in Ihrem Browser verschlüsselt, was jede Entschlüsselung auf dem Retrospected Server unmöglich macht." + }, + "privateSessions": { + "title": "Private Sitzungen", + "description": "Stellen Sie sicher, dass nur autorisierte Personen auf Ihre Sitzung zugreifen können." + }, + "unlimitedPosts": { + "title": "Unbegrenzte Beiträge", + "description": "Mit einem Pro-Abonnement erhalten Sie unbegrenzte Beiträge." + } + }, + "subscribeButton": "Abonnieren", + "payButton": "Auswählen", + "cancelButton": "Abbrechen", + "startTrial": "30-Tage Testversion" + }, + "Products": { + "team": "Perfekt für kleinere Teams, können Sie bis zu 20 Kollegen auswählen, die auf ein Pro-Konto aktualisiert werden.", + "unlimited": "Wenn Sie eine größere Firma sind, werden Sie eine unbegrenzte Anzahl von Pro-Konten haben.", + "self-hosted": "Retrospected on premises, one-time fee and unlimited updates. Keep complete control of your data for ey.", + "users": "{{users}} Benutzer", + "unlimited_seats": "Unbegrenzt", + "month": "monat", + "year": "jahr", + "wantToPayYearly": "Ich möchte jährlich bezahlen (alle 12 Monate) und einen Monat gratis pro Jahr!" + }, + "Encryption": { + "createEncryptedSession": "Verschlüsselte Sitzung", + "sessionNotEncrypted": "Diese Sitzung ist nicht verschlüsselt.", + "sessionEncryptedHaveKeyTooltip": "Diese Sitzung ist verschlüsselt und der Schlüssel wird in Ihrem Browser gespeichert. Sie können diese Sitzung öffnen, ohne das Passwort erneut eingeben zu müssen.", + "sessionEncryptedNoKeyTooltip": "Diese Sitzung ist verschlüsselt und der Schlüssel wird nicht in Ihrem Browser gespeichert. Sie werden beim Öffnen dieser Sitzung nach dem Entschlüsselungsschlüssel gefragt.", + "sessionEncryptedWrongKeyTooltip": "Diese Sitzung ist verschlüsselt und der Schlüssel, den Sie gespeichert haben, ist nicht der richtige Schlüssel.", + "newEncryptedSessionWarningTitle": "Diese Sitzung ist lokal verschlüsselt", + "newEncryptedSessionWarningContent": "Es ist sehr wichtig, dass Sie die vollständige URL (die den Schlüssel enthält) irgendwo sicher speichern oder zumindest der Verschlüsselungsschlüssel: {{key}}. Wenn Sie diesen Schlüssel verlieren, gibt es nichts, was getan werden kann, um die Daten abzurufen.", + "sessionEncryptionError": "Diese Sitzung ist verschlüsselt und Sie scheinen den Entschlüsselungsschlüssel nicht lokal speichern zu lassen. Bitte verwenden Sie den ursprünglichen Link, einschließlich des Entschlüsselungsschlüssels.", + "passwordModalTitle": "Verschlüsselte Sitzung - Passwort eingeben", + "passwordModelIncorrect": "Der Verschlüsselungsschlüssel ist falsch." + }, + "Private": { + "lockSuccessNotification": "Ihre Sitzung wurde erfolgreich privat gemacht. Keine neuen Teilnehmer können beitreten.", + "unlockSuccessNotification": "Ihre Sitzung wurde erfolgreich öffentlich gemacht. Jeder kann beitreten.", + "lockButton": "Privat machen", + "unlockButton": "Öffentlich machen", + "lockDescription": "Sie sind dabei, die Sitzung privat zu machen. Nur die aktuellen Teilnehmer (unten aufgeführt) haben Zugang zu dieser Sitzung, sobald sie gesperrt sind.", + "cancelButton": "Abbrechen", + "sessionLockedTitle": "Diese Sitzung ist privat.", + "sessionLockedDescription": "Bitte den Moderator bitten, ihn zu entsperren, damit du beitreten kannst. Dann aktualisiere diese Seite.", + "sessionNonProTitle": "Diese Sitzung ist nur für Pro-Benutzer zugänglich", + "sessionNonProDescription": "Diese Sitzung verwendet Funktionen, die nur Pro-Nutzern zur Verfügung stehen. Bitte fragen Sie den Moderator oder den Abonnementhalter, Ihnen ein Pro-Konto zu erteilen.", + "sessionIsPublic": "Diese Sitzung ist öffentlich und für jedermann zugänglich.", + "sessionIsPrivate": "Diese Sitzung ist privat und Sie haben Zugriff.", + "sessionIsPrivateNoAccess": "Diese Sitzung ist privat, aber Sie haben keinen Zugriff." + }, + "TrialPrompt": { + "allowanceReachedTitle": "Sie haben Ihr Freigepäck erreicht", + "allowanceReachedDescription": "Um unbegrenzte Beiträge zu erhalten, abonnieren Sie bitte Retrospected Pro", + "nearEndAllowanceTitle": "Sie nähern sich dem Ende Ihres Kontingents", + "nearEndAllowanceDescription": "Du hast noch ca. {{quota}} Beiträge übrig", + "onTrialTitle": "Retrospected Pro - Testversion", + "remainingTrialSentence": "Du hast noch {{remaining}} in deiner Testversion hinterlassen.", + "trialEndedTitle": "Deine Retrospected Pro Testversion ist beendet", + "trialEndedSentence": "Abonnieren Sie noch heute, um den Zugriff auf die Pro-Funktionen wiederherzustellen.", + "subscribeNow": "Jetzt abonnieren!" + }, + "Chat": { + "writeAMessage": "Hier eine Nachricht schreiben..." + } +} \ No newline at end of file diff --git a/frontend/src/translations/locales/en-GB.json b/frontend/src/translations/locales/en-GB.json new file mode 100644 index 000000000..e607597fc --- /dev/null +++ b/frontend/src/translations/locales/en-GB.json @@ -0,0 +1,423 @@ +{ + "Header": { + "subtitle": "A good way of expressing oneself in an Agile way", + "logout": "Logout", + "leave": "Leave", + "summaryMode": "Summary Mode", + "account": "My Account", + "adminPanel": "Administration Panel" + }, + "LanguagePicker": { + "header": "Choose a language" + }, + "Main": { + "hint": "You can invite others to this session by copy-pasting the URL" + }, + "Home": { + "welcome": "Welcome, {{name}}" + }, + "PreviousGame": { + "createdBy": "Created by", + "posts_one": "post", + "posts_other": "posts", + "participants_one": "participant", + "participants_other": "participants", + "votes_one": "vote", + "votes_other": "votes", + "actions_one": "action", + "actions_other": "actions" + }, + "Column": { + "createGroupTooltip": "Create a group to group posts together" + }, + "Group": { + "emptyGroupTitle": "This is an empty group", + "emptyGroupContent": "Move a post here to fill this group" + }, + "Post": { + "openExtra": "Additional features", + "closeExtra": "Close", + "vote": "vote", + "votes": "votes", + "deleteButton": "Delete", + "setActionButton": "Set Action", + "setGiphyButton": "Choose a Giphy image", + "noContent": "(This post has no content)", + "by": "by", + "upVote": "up-vote", + "downVote": "down-vote", + "voteRemainingMultiple": "You have {{number}} {{type}}s remaining.", + "voteRemainingOne": "You only have one {{type}} remaining, make it count!", + "voteRemainingNone": "You don't have any {{type}} remaining.", + "toggleGiphyButton": "Toggle Giphy image" + }, + "Customize": { + "title": "Customise your Session", + "votingCategory": "Voting", + "votingCategorySub": "Set the rules about likes and dislikes", + "postCategory": "Post settings", + "postCategorySub": "Set the rules about what a user can do when creating or viewing a post", + "customTemplateCategory": "Column Template", + "customTemplateCategorySub": "Set the number of columns and their characteristics", + "startButton": "Start the session", + "editButton": "Update", + "maxUpVotes": "Max Up-Votes", + "maxUpVotesHelp": "Maximum number of 'likes' votes a user is allowed to cast", + "maxDownVotes": "Max Down-Votes", + "maxDownVotesHelp": "Maximum number of 'dislikes' votes a user is allowed to cast", + "maxPosts": "Max Posts per user", + "maxPostsHelp": "Maximum number of posts a user can create per session", + "allowSelfVoting": "Allow Self Voting", + "allowSelfVotingHelp": "Whether to allow a user to vote on their own post", + "allowMultipleVotes": "Allow Multiple Votes", + "allowMultipleVotesHelp": "Whether to allow a user to vote multiple times on the same post", + "allowActions": "Allow Actions", + "allowActionsHelp": "Whether to allow the 'Action' (follow-up) field on each post", + "allowAuthorVisible": "Show Author", + "allowAuthorVisibleHelp": "Display the author of the post, on the post itself.", + "newPostsFirst": "Add new posts first", + "newPostsFirstHelp": "New posts are added at the top of the column", + "allowGiphy": "Allow Giphy", + "allowGiphyHelp": "Allow users to set a Giphy image against a post", + "allowGrouping": "Allow Grouping", + "allowGroupingHelp": "Allow the creation of groups to group posts together", + "allowReordering": "Allow Re-ordering", + "allowReorderingHelp": "Allow re-ordering posts by drag-and-drop", + "blurCards": "Blur Cards", + "blurCardsHelp": "Cards content is blurred until the moderator reveals the content", + "template": "Template", + "templateHelp": "Use a pre-defined set of columns", + "numberOfColumns": "Number of columns", + "numberOfColumnsHelp": "Set the number of columns", + "makeDefaultTemplate": "Make this my default template" + }, + "PostBoard": { + "customQuestion": "Custom Column", + "notWellQuestion": "What could be improved?", + "wellQuestion": "What went well?", + "ideasQuestion": "A brilliant idea to share?", + "startQuestion": "Start", + "stopQuestion": "Stop", + "continueQuestion": "Continue", + "likedQuestion": "Liked", + "lackedQuestion": "Lacked", + "learnedQuestion": "Learned", + "longedForQuestion": "Longed For", + "anchorQuestion": "Anchor", + "boatQuestion": "Boat", + "islandQuestion": "Island", + "windQuestion": "Wind", + "rockQuestion": "Rock", + "disconnected": "You have been disconnected from the current session.", + "reconnect": "Reconnect", + "notLoggedIn": "You are not logged in. You can view this session as a spectator, but must login to participate.", + "error_action_unauthorised": "You are not allowed to perform this action.", + "error_cannot_edit_group": "Editing the group failed.", + "error_cannot_edit_post": "Editing the post failed.", + "error_cannot_get_session": "Could not get the session data. Please reload the page.", + "error_cannot_register_vote": "Your vote was not registered successfully.", + "error_cannot_save_group": "The group you created could not be saved.", + "error_cannot_save_post": "The post you created could not be saved.", + "error_cannot_delete_group": "The group could not be deleted", + "error_cannot_delete_post": "The post could not be deleted", + "error_cannot_rename_session": "Renaming the session failed", + "error_cannot_save_columns": "Saving columns failed", + "error_cannot_save_options": "Saving options failed", + "maxPostsReached": "You have reached the maximum number of posts set by the moderator.", + "iAmDone": "I'm done!", + "iAmNotDoneYet": "I'm not done yet...", + "userIsReady": "{{user}} is ready!" + }, + "GameMenu": { + "board": "Board", + "summary": "Summary" + }, + "Template": { + "default": "Default", + "wellNotWell": "Well / Not Well", + "startStopContinue": "Start / Stop / Continue", + "fourLs": "Four Ls", + "sailboat": "Sailboat" + }, + "Clients": { + "header": "Participants:", + "joined": "{{users}} joined.", + "left": "{{users}} left." + }, + "Join": { + "welcome": "Welcome to Retrospected", + "standardTab": { + "header": "Create", + "text": "Click below and start retrospecting:", + "button": "Create a new session", + "customizeButton": "Customise" + }, + "optionsTab": { + "header": "Options", + "input": "Name", + "button": "Create custom session" + }, + "previousTab": { + "header": "Previous", + "rejoinButton": "Rejoin" + } + }, + "AnonymousLogin": { + "namePlaceholder": "Please enter a name or nickname here to continue", + "buttonLabel": "Login", + "header": "Login", + "anonymousAuthHeader": "Anonymous Login", + "anonymousAuthDescription": "This will create an anonymous account. Some features won't be available.", + "authenticatingWith": "Authenticating with", + "or": "or" + }, + "SocialMediaLogin": { + "header": "OAuth", + "info": "This will use a third party provider of your choosing to authenticate you. No password is stored." + }, + "AuthCommon": { + "emailField": "E-mail", + "passwordField": "Password", + "nameField": "Your name (for display purposes)", + "passwordScoreWords": [ + "weak", + "weak", + "not quite", + "good", + "strong" + ] + }, + "AccountLogin": { + "header": "Password", + "loginButton": "Login", + "info": "Login with your email and password.", + "registerLink": "Not registered? Click here", + "forgotPasswordLink": "Forgot your password?", + "errorEmailPasswordIncorrect": "Your credentials are incorrect." + }, + "Register": { + "header": "Register", + "info": "Get yourself a Retrospected account!", + "registerButton": "Register", + "errorAlreadyRegistered": "This email is already registered", + "errorGeneral": "An error occurred while trying to create your account.", + "messageSuccess": "Thank you! You should receive an email shortly to validate your account.", + "errorInvalidEmail": "Please enter a valid email" + }, + "ValidateAccount": { + "success": "Your email has been correctly validated. I'm going to log you in in a sec!", + "error": "There was an error validating your email.", + "loading": "We are validating your email. Please wait." + }, + "ResetPassword": { + "doneMessage": "Done! Have a look in your emails, you should get a link to reset your password.", + "header": "Password Reset", + "resetButton": "Reset Password", + "info": "Forgot your password? Not a problem. Enter your email below and you'll get a reset email prompto.", + "success": "Your password has been updated. I'm going to log you in in a sec!", + "error": "There was an error updating your password.", + "loading": "We are updating your password. Please wait.", + "resetInfo": "Please provide a new password" + }, + "SummaryBoard": { + "noPosts": "There are no posts to display", + "copyAsMarkdown": "Copy the summary as Markdown", + "copyAsRichText": "Copy the summary as Rich Text", + "copySuccessful": "You successfully copied your summary in your clipboard" + }, + "SessionName": { + "defaultSessionName": "My Retrospective" + }, + "Invite": { + "inviteButton": "Invite", + "dialog": { + "title": "Invite people to your retrospective", + "text": "To invite people to your retrospected session, simply send them the following URL", + "copyButton": "Copy URL to Clipboard" + } + }, + "Generic": { + "ok": "OK", + "cancel": "Cancel" + }, + "Actions": { + "tooltip": "Create an action on the back of this item", + "label": "Open the Action panel", + "summaryTitle": "Your Actions", + "title": "Action" + }, + "DeleteSession": { + "header": "Deleting '{{name}}'?", + "firstLine": "Deleting a session is irreversible. It will delete all posts, votes, groups, and the session itself. The data cannot be restored.", + "secondLine": "Are you sure you want to delete this session and all its content?", + "yesImSure": "Yes, I'm sure", + "cancel": "No, I'm sorry, I made a mistake" + }, + "RevealCards": { + "buttonLabel": "Reveal", + "dialogTitle": "Reveal all cards", + "dialogContent": "This will reveal all blurred cards for everyone. This cannot be undone.", + "confirmButton": "Let's reveal!", + "cancelButton": "No thanks" + }, + "AccountPage": { + "anonymousError": "Anonymous accounts cannot have access to their profile (because they don't have one).", + "details": { + "header": "Your Details", + "username": "Username", + "email": "Email", + "accountType": "Account Type" + }, + "plan": { + "header": "Your Plan", + "plan": "Plan", + "youAreOwner": "You are the owner of this plan, through the subscription below.", + "youAreMember": "You are on this plan through somebody else's subscription." + }, + "subscription": { + "header": "Your Subscription", + "manageButton": "Manage my subscription", + "membersEditor": { + "title": "Your Team", + "limitReached": "You reached the limit of your subscription ({{limit}} users, including yourself). Please remove members, or upgrade to an unlimited Company account.", + "info": "Add emails below to grant Pro accounts to up to {{limit}} other colleagues. Press Enter after each email address." + } + }, + "trial": { + "header": "Your Trial", + "yourTrialWillExpireIn": "Your trial will end in {{date}}.", + "subscribe": "Subscribe now" + }, + "deleteAccount": { + "title": "GDPR", + "warning": "You have the right to be forgotten. That being said, be careful when deleting your account. This cannot be undone.", + "deleteData": "Delete my data", + "modal": { + "confirm": { + "title": "Are you absolutely sure?", + "description": "There is no going back on this.", + "confirmation": "Yes I want to delete all my data", + "cancellation": "Get me out of here" + }, + "subheader": "Choose what to delete", + "deleteAccount": "Delete your account and any identities linked to your email.", + "recommended": "Recommended", + "deleteSessions": { + "main": "Should we delete the sessions (retrospectives) you have created?", + "selected": "Your sessions and all their data, including other people's posts and votes, will be permanently deleted.", + "unselected": "Your sessions will be kept and their author will become an anonymous user." + }, + "deletePosts": { + "main": "Should we delete all the posts you wrote?", + "selected": "Your posts, in any session, and their associated votes and actions will be permanently deleted.", + "unselected": "Your posts will be kept, but they will become associated with an anonymous user." + }, + "deleteVotes": { + "main": "Should we also delete all your votes?", + "selected": "Your votes, in all sessions will be permanently deleted.", + "unselected": "Your votes will be kept, but they will become associated with an anonymous user." + }, + "deleteAccountButton": "DELETE YOUR ACCOUNT", + "cancelButton": "Cancel" + } + } + }, + "SubscribePage": { + "alertAlreadyPro": "You already are a Pro user, so you might not need another subscription.", + "alertAlreadySubscribed": "You already have a subscription, so you might not need another subscription.", + "currency": { + "title": "Currency", + "description": "Pick a currency you would like to be billed with", + "warning": "Your account is already set to use {{currency}}, so you cannot change the currency anymore." + }, + "plan": { + "title": "Plan", + "description": "Choose the plan that fits your use case!" + }, + "domain": { + "title": "Domain", + "description": "Your unlimited subscription applies to a given domain. Any user with this email domain will automatically become a Pro user.", + "invalidDomain": "Please provide a valid domain. The domain cannot be a free or disposable email domain." + }, + "subscribe": { + "title": "Checkout", + "description": "You will be redirected to our partner, Stripe, for payment", + "cannotRegisterWithAnon": "You need to be logged in with an OAuth or Password account to continue.", + "checkout": "Checkout" + } + }, + "SubscribeModal": { + "title": "Pro Subscription", + "header": "Retrospected Pro", + "description": "Protect your company's data by subscribing to Retrospected Pro. With Retrospected Pro, get the following features and more:", + "features": { + "encryptedSession": { + "title": "Encrypted Sessions", + "description": "Your data is encrypted in your browser, making any decryption impossible on the Retrospected server." + }, + "privateSessions": { + "title": "Private Sessions", + "description": "Make sure only authorised people can access your session." + }, + "unlimitedPosts": { + "title": "Unlimited Posts", + "description": "With a Pro subscription, get unlimited posts." + } + }, + "subscribeButton": "Subscribe", + "payButton": "Select", + "cancelButton": "Cancel", + "startTrial": "30-day Trial" + }, + "Products": { + "team": "Perfect for smaller teams, you can select up to 20 colleagues who will be upgraded to a Pro account.", + "unlimited": "If you are a bigger company, you will enjoy an unlimited number of Pro accounts.", + "self-hosted": "Retrospected on premises, one-time fee and unlimited updates. Keep total control of your data, for ever.", + "users": "{{users}} users", + "unlimited_seats": "Unlimited", + "month": "month", + "year": "year", + "wantToPayYearly": "I want to pay annually (every 12 months), and get one month free per year!" + }, + "Encryption": { + "createEncryptedSession": "Encrypted Session", + "sessionNotEncrypted": "This session is not encrypted.", + "sessionEncryptedHaveKeyTooltip": "This session is encrypted, and the key is stored in your browser. You can open this session without having to provide the password again.", + "sessionEncryptedNoKeyTooltip": "This session is encrypted, and the key is not stored in your browser. You will be asked for the decryption key when opening this session.", + "sessionEncryptedWrongKeyTooltip": "This session is encrypted, and the key you have stored is not the correct key.", + "newEncryptedSessionWarningTitle": "This session is encrypted locally", + "newEncryptedSessionWarningContent": "It is very important for you to save the full URL (which contains the key) somewhere safe, or at least the encryption key: {{key}}. If you lose this encryption key, there is nothing that can be done to retrieve the data.", + "sessionEncryptionError": "This session is encrypted, and you don't seem to have the decryption key stored locally. Please use the original link, including the decryption key.", + "passwordModalTitle": "Encrypted Session - Enter Password", + "passwordModelIncorrect": "The encryption key is incorrect." + }, + "Private": { + "lockSuccessNotification": "Your session has been successfuly made private. No new participants can join.", + "unlockSuccessNotification": "Your session has been successfuly made public. Anyone can join.", + "lockButton": "Make Private", + "unlockButton": "Make Public", + "lockDescription": "You are about to make the session private. Only the current participants (listed below) will be allowed access to this session once locked.", + "cancelButton": "Cancel", + "sessionLockedTitle": "This session is private.", + "sessionLockedDescription": "Please ask its moderator to unlock it so you can join. Then, refresh this page.", + "sessionNonProTitle": "This session is only accessible to Pro users", + "sessionNonProDescription": "This session uses features only available to Pro users. Please ask the moderator or subscription holder to give you a Pro account.", + "sessionIsPublic": "This session is public and accessible to anyone.", + "sessionIsPrivate": "This session is private, and you have access.", + "sessionIsPrivateNoAccess": "This session is private, but you do not have access." + }, + "TrialPrompt": { + "allowanceReachedTitle": "You have reached your free allowance", + "allowanceReachedDescription": "In order to get unlimited posts, please subscribe to Retrospected Pro", + "nearEndAllowanceTitle": "You are nearing the end of your quota", + "nearEndAllowanceDescription": "You have about {{quota}} posts left", + "onTrialTitle": "Retrospected Pro - Trial", + "remainingTrialSentence": "You have {{remaining}} left on your trial.", + "trialEndedTitle": "Your Retrospected Pro Trial has ended", + "trialEndedSentence": "Subscribe today to regain access to the Pro features.", + "subscribeNow": "Subscribe now!" + }, + "Chat": { + "writeAMessage": "Write a message here..." + } +} \ No newline at end of file diff --git a/frontend/src/translations/locales/es-ES.json b/frontend/src/translations/locales/es-ES.json new file mode 100644 index 000000000..d83ffaa44 --- /dev/null +++ b/frontend/src/translations/locales/es-ES.json @@ -0,0 +1,423 @@ +{ + "Header": { + "subtitle": "Una buena manera de despotricar ordenadamente", + "logout": "Cerrar sesión", + "leave": "Salir", + "summaryMode": "Modo resumido", + "account": "Mi cuenta", + "adminPanel": "Panel de administración" + }, + "LanguagePicker": { + "header": "Escoje un idioma" + }, + "Main": { + "hint": "Puedes invitar a otros a esta sesión compartiendo la URL" + }, + "Home": { + "welcome": "Bienvenido, {{name}}" + }, + "PreviousGame": { + "createdBy": "Creado por", + "posts_one": "post", + "posts_other": "mensajes", + "participants_one": "participante", + "participants_other": "participantes", + "votes_one": "votar", + "votes_other": "votos", + "actions_one": "acción", + "actions_other": "acciones" + }, + "Column": { + "createGroupTooltip": "Crear un grupo para agrupar publicaciones juntas" + }, + "Group": { + "emptyGroupTitle": "Este es un grupo vacío", + "emptyGroupContent": "Mover un mensaje aquí para llenar este grupo" + }, + "Post": { + "openExtra": "Características adicionales", + "closeExtra": "Cerrar", + "vote": "votar", + "votes": "votos", + "deleteButton": "Suprimir", + "setActionButton": "Definir acción", + "setGiphyButton": "Elige una imagen de Giphy", + "noContent": "(Esta publicacion no tiene contenido)", + "by": "por", + "upVote": "voto positivo", + "downVote": "voto negativo", + "voteRemainingMultiple": "Tienes {{number}} {{type}}s restantes.", + "voteRemainingOne": "Solo te queda un {{type}} restante, ¡hazlo contar!", + "voteRemainingNone": "No te quedan {{type}}.", + "toggleGiphyButton": "Cambiar imagen de Giphy" + }, + "Customize": { + "title": "Personaliza tu sesión", + "votingCategory": "Votaciones", + "votingCategorySub": "Establecer las reglas sobre \"me gusta\" y \"me gusta\"", + "postCategory": "Ajustes de publicación", + "postCategorySub": "Establecer las reglas sobre lo que un usuario puede hacer al crear o ver un mensaje", + "customTemplateCategory": "Plantilla de columna", + "customTemplateCategorySub": "Establecer el número de columnas y sus características", + "startButton": "Iniciar la sesión", + "editButton": "Actualizar", + "maxUpVotes": "Máximo de votos", + "maxUpVotesHelp": "Número máximo de votos 'likes' que un usuario puede emitir", + "maxDownVotes": "Descensos máximos", + "maxDownVotesHelp": "Número máximo de votos 'no me gusta' que un usuario puede emitir", + "maxPosts": "Máximo de mensajes por usuario", + "maxPostsHelp": "Número máximo de mensajes que un usuario puede crear por sesión", + "allowSelfVoting": "Permitir voto propio", + "allowSelfVotingHelp": "Si permitir que un usuario vote en su propio post", + "allowMultipleVotes": "Permitir múltiples votos", + "allowMultipleVotesHelp": "Si permitir que un usuario vote varias veces en el mismo post", + "allowActions": "Permitir acciones", + "allowActionsHelp": "Si permitir o no el campo 'Acción' (seguimiento) en cada publicación", + "allowAuthorVisible": "Mostrar autor", + "allowAuthorVisibleHelp": "Mostrar el autor de la publicación, en el propio mensaje.", + "newPostsFirst": "Añadir nuevos posts primero", + "newPostsFirstHelp": "Nuevos mensajes se añaden en la parte superior de la columna", + "allowGiphy": "Permitir Giphy", + "allowGiphyHelp": "Permitir a los usuarios establecer una imagen de Giphy en un post", + "allowGrouping": "Permitir agrupar", + "allowGroupingHelp": "Permitir la creación de grupos agrupar mensajes juntos", + "allowReordering": "Permitir reordenar", + "allowReorderingHelp": "Permitir reordenar mensajes por arrastrar y soltar", + "blurCards": "Desenfocar tarjetas", + "blurCardsHelp": "El contenido de las tarjetas está desenfocado hasta que el moderador revele el contenido", + "template": "Plantilla", + "templateHelp": "Usar un conjunto predefinido de columnas", + "numberOfColumns": "Número de columnas", + "numberOfColumnsHelp": "Establecer el número de columnas", + "makeDefaultTemplate": "Hacer esta mi plantilla predeterminada" + }, + "PostBoard": { + "customQuestion": "Columna personalizada", + "notWellQuestion": "Qué se podría mejorar?", + "wellQuestion": "Qué ha ido bien?", + "ideasQuestion": "Una brillante idea que compartir?", + "startQuestion": "Comenzar", + "stopQuestion": "Parar", + "continueQuestion": "Continuar", + "likedQuestion": "Me gustó", + "lackedQuestion": "Atraído", + "learnedQuestion": "Aprendido", + "longedForQuestion": "Lanzado para", + "anchorQuestion": "Ancla", + "boatQuestion": "Barco", + "islandQuestion": "Isla", + "windQuestion": "Viento", + "rockQuestion": "Roca", + "disconnected": "Has sido desconectado de la sesión actual.", + "reconnect": "Volver a conectar", + "notLoggedIn": "No estás conectado. Puedes ver esta sesión como un espectador, pero debes iniciar sesión para participar.", + "error_action_unauthorised": "No tienes permisos para realizar esta acción.", + "error_cannot_edit_group": "Falló la edición del grupo.", + "error_cannot_edit_post": "Error al editar el mensaje.", + "error_cannot_get_session": "No se pudo obtener los datos de la sesión. Por favor, vuelva a cargar la página.", + "error_cannot_register_vote": "Tu voto no se ha registrado correctamente.", + "error_cannot_save_group": "El grupo creado no pudo ser guardado.", + "error_cannot_save_post": "No se pudo guardar la publicación que creó.", + "error_cannot_delete_group": "El grupo no pudo ser eliminado", + "error_cannot_delete_post": "No se ha podido eliminar la publicación", + "error_cannot_rename_session": "Fallo al renombrar la sesión", + "error_cannot_save_columns": "Error al guardar columnas", + "error_cannot_save_options": "Fallo al guardar opciones", + "maxPostsReached": "Has alcanzado el número máximo de mensajes establecidos por el moderador.", + "iAmDone": "¡He terminado!", + "iAmNotDoneYet": "No he terminado todavía...", + "userIsReady": "¡{{user}} está listo!" + }, + "GameMenu": { + "board": "Tablero", + "summary": "Summary" + }, + "Template": { + "default": "Por defecto", + "wellNotWell": "Bueno / No Bueno", + "startStopContinue": "Inicio / Parar / Continuar", + "fourLs": "Cuatro Ls", + "sailboat": "Barco de vela" + }, + "Clients": { + "header": "Acompañenos amablemente en este momento:", + "joined": "{{users}} se ha unido.", + "left": "{{users}} restante." + }, + "Join": { + "welcome": "Bienvenido a la retrospectiva", + "standardTab": { + "header": "Crear una sesión", + "text": "Pulse abajo y empieze la retrospectiva:", + "button": "Crear una sesión nueva", + "customizeButton": "Personalizar" + }, + "optionsTab": { + "header": "Avanzado", + "input": "inserte un nombre para su sesión", + "button": "Crear una sesión personalizada" + }, + "previousTab": { + "header": "Sesiones anteriores", + "rejoinButton": "Reunirse" + } + }, + "AnonymousLogin": { + "namePlaceholder": "Quién eres exáctamente? Inserta tu nombre aquí", + "buttonLabel": "Empezemos", + "header": "Ingresar", + "anonymousAuthHeader": "Inicio de sesión anónimo", + "anonymousAuthDescription": "Esto creará una cuenta anónima. Algunas características no estarán disponibles.", + "authenticatingWith": "Autenticando con", + "or": "o" + }, + "SocialMediaLogin": { + "header": "OAuth", + "info": "Esto utilizará un proveedor de terceros de su elección para autenticarse. No hay contraseña almacenada." + }, + "AuthCommon": { + "emailField": "E-mail", + "passwordField": "Contraseña", + "nameField": "Tu nombre (por motivos de visualización)", + "passwordScoreWords": [ + "débil", + "débil", + "no muy bien", + "bueno", + "fuerte" + ] + }, + "AccountLogin": { + "header": "Contraseña", + "loginButton": "Ingresar", + "info": "Inicia sesión con tu correo electrónico y contraseña.", + "registerLink": "¿No está registrado? Haga clic aquí", + "forgotPasswordLink": "¿Olvidaste tu contraseña?", + "errorEmailPasswordIncorrect": "Sus credenciales son incorrectas." + }, + "Register": { + "header": "Registrarse", + "info": "¡Obtén una cuenta Retrospectiva!", + "registerButton": "Registrarse", + "errorAlreadyRegistered": "Este correo electrónico ya está registrado", + "errorGeneral": "Ocurrió un error mientras se trataba de crear su cuenta.", + "messageSuccess": "¡Gracias! En breve recibirás un correo electrónico para validar tu cuenta.", + "errorInvalidEmail": "Por favor ingrese un email válido" + }, + "ValidateAccount": { + "success": "Tu correo electrónico ha sido validado correctamente. ¡Voy a iniciar sesión en un segundo!", + "error": "Hubo un error al validar tu correo electrónico.", + "loading": "Estamos validando tu correo electrónico. Por favor, espera." + }, + "ResetPassword": { + "doneMessage": "¡Hecho! Echa un vistazo en tus correos electrónicos, deberías obtener un enlace para restablecer tu contraseña.", + "header": "Restablecer contraseña", + "resetButton": "Restablecer contraseña", + "info": "¿Olvidaste tu contraseña? No es un problema. Introduce tu correo electrónico a continuación y obtendrás un cambio de dirección de correo electrónico.", + "success": "Su contraseña ha sido actualizada. ¡Voy a iniciar sesión en un segundo!", + "error": "Se ha producido un error al actualizar su contraseña.", + "loading": "Estamos actualizando tu contraseña. Por favor, espera.", + "resetInfo": "Por favor proporcione una nueva contraseña" + }, + "SummaryBoard": { + "noPosts": "No hay publicaciones que mostrar", + "copyAsMarkdown": "Copiar el resumen como Markdown", + "copyAsRichText": "Copiar el resumen como texto enriquecido", + "copySuccessful": "Has copiado correctamente tu resumen en tu portapapeles" + }, + "SessionName": { + "defaultSessionName": "Mi retrospectiva" + }, + "Invite": { + "inviteButton": "Invitar", + "dialog": { + "title": "Invitar personas a tu retrospectiva", + "text": "Para invitar otras personas a tu retrospectiva, sencillamente enviales la siguiente URL.", + "copyButton": "Copiar la URL al Portapapeles" + } + }, + "Generic": { + "ok": "Ok", + "cancel": "Cancelar" + }, + "Actions": { + "tooltip": "Crear una acción", + "label": "Abre el panel de acción.", + "summaryTitle": "Tus acciones", + "title": "Acción" + }, + "DeleteSession": { + "header": "¿Eliminar '{{name}}'?", + "firstLine": "La eliminación de una sesión es irreversible. Se eliminarán todos los mensajes, votos, grupos y la sesión misma. Los datos no se pueden restaurar.", + "secondLine": "¿Está seguro que desea eliminar esta sesión y todo su contenido?", + "yesImSure": "Sí, estoy seguro", + "cancel": "No, lo siento, cometí un error" + }, + "RevealCards": { + "buttonLabel": "Revelar", + "dialogTitle": "Mostrar todas las tarjetas", + "dialogContent": "Esto revelará todas las cartas borrosas para todos. Esto no se puede deshacer.", + "confirmButton": "¡Vamos a revelar!", + "cancelButton": "No gracias" + }, + "AccountPage": { + "anonymousError": "Las cuentas anónimas no pueden tener acceso a su perfil (porque no tienen una).", + "details": { + "header": "Tus detalles", + "username": "Usuario", + "email": "E-mail", + "accountType": "Tipo de cuenta" + }, + "plan": { + "header": "Su plan", + "plan": "Plano", + "youAreOwner": "Usted es el propietario de este plan, a través de la suscripción a continuación.", + "youAreMember": "Estás en este plan a través de la suscripción de otra persona." + }, + "subscription": { + "header": "Tu suscripción", + "manageButton": "Administrar mi suscripción", + "membersEditor": { + "title": "Tu equipo", + "limitReached": "Has alcanzado el límite de tu suscripción ({{limit}} usuarios, incluido tú mismo). Por favor, elimina miembros o actualiza a una cuenta de empresa ilimitada.", + "info": "Añada correos electrónicos a continuación para conceder cuentas Pro hasta {{limit}} otras opciones. Pulse Intro después de cada dirección de correo electrónico." + } + }, + "trial": { + "header": "Tu prueba", + "yourTrialWillExpireIn": "Tu periodo de prueba terminará en {{date}}.", + "subscribe": "Suscríbete ahora" + }, + "deleteAccount": { + "title": "GDPR", + "warning": "Tienes derecho a ser olvidado. Dicho esto, ten cuidado al eliminar tu cuenta. Esto no se puede deshacer.", + "deleteData": "Eliminar mis datos", + "modal": { + "confirm": { + "title": "¿Estás absolutamente seguro?", + "description": "No hay vuelta atrás en esto.", + "confirmation": "Sí, quiero eliminar todos mis datos", + "cancellation": "Sígueme de aquí" + }, + "subheader": "Elegir qué borrar", + "deleteAccount": "Elimina tu cuenta y cualquier identidad vinculada a tu correo electrónico.", + "recommended": "Recomendado", + "deleteSessions": { + "main": "¿Deberíamos eliminar las sesiones (retrospectivas) que has creado?", + "selected": "Sus sesiones y todos sus datos, incluyendo los mensajes y votos de otras personas, serán eliminados permanentemente.", + "unselected": "Sus sesiones se mantendrán y su autor se convertirá en un usuario anónimo." + }, + "deletePosts": { + "main": "¿Deberíamos eliminar todos los mensajes que quieras?", + "selected": "Tus mensajes, en cualquier sesión, y sus votos y acciones asociados serán eliminados permanentemente.", + "unselected": "Tus mensajes serán descontados, pero se asociarán con un usuario anónimo." + }, + "deleteVotes": { + "main": "¿Deberíamos también eliminar todos sus votos?", + "selected": "Sus votos, en todas las sesiones se eliminarán permanentemente.", + "unselected": "Tus votos serán contundentes, pero se asociarán con un usuario anónimo." + }, + "deleteAccountButton": "ELIMINAR TU CUENTA", + "cancelButton": "Cancelar" + } + } + }, + "SubscribePage": { + "alertAlreadyPro": "Ya eres un usuario Pro, así que puede que no necesites otra suscripción.", + "alertAlreadySubscribed": "Ya tienes una suscripción, así que puede que no necesites otra suscripción.", + "currency": { + "title": "Moneda", + "description": "Elige una moneda con la que te gustaría ser facturada", + "warning": "Tu cuenta ya está configurada para usar {{currency}}, por lo que ya no puedes cambiar la divisa." + }, + "plan": { + "title": "Plano", + "description": "¡Elija el plan que se ajuste a su caso de uso!" + }, + "domain": { + "title": "Dominio", + "description": "Tu suscripción ilimitada se aplica a un dominio determinado. Cualquier usuario con este dominio de correo electrónico se convertirá automáticamente en un usuario Pro.", + "invalidDomain": "Por favor, proporcione un dominio válido. El dominio no puede ser un dominio de correo electrónico libre o desechable." + }, + "subscribe": { + "title": "Pedido", + "description": "Serás redirigido a nuestro socio, Stripe, por pago", + "cannotRegisterWithAnon": "Necesitas iniciar sesión con una cuenta de OAuth o Contraseña para continuar.", + "checkout": "Pedido" + } + }, + "SubscribeModal": { + "title": "Suscripción Pro", + "header": "Reprobado Pro", + "description": "Protege los datos de tu empresa suscribiéndote a Retrospected Pro. Con Retrospected Pro, consigue las siguientes características y más:", + "features": { + "encryptedSession": { + "title": "Sesiones cifradas", + "description": "Sus datos están cifrados en su navegador, haciendo imposible cualquier descifrado en el servidor Retrospecto." + }, + "privateSessions": { + "title": "Sesiones Privadas", + "description": "Asegúrese de que sólo las personas autorizadas pueden acceder a su sesión." + }, + "unlimitedPosts": { + "title": "Mensajes ilimitados", + "description": "Con una suscripción Pro, obtén mensajes ilimitados." + } + }, + "subscribeButton": "Suscribirse", + "payButton": "Seleccionar", + "cancelButton": "Cancelar", + "startTrial": "Prueba de 30 días" + }, + "Products": { + "team": "Perfecto para equipos más pequeños, puedes seleccionar hasta 20 colegas que serán actualizados a una cuenta Pro.", + "unlimited": "Si eres una empresa más grande, disfrutarás de un número ilimitado de cuentas Pro.", + "self-hosted": "Retrospectivamente en casas, honorarios únicos y actualizaciones ilimitadas. Mantén el control total de tus datos para siempre.", + "users": "{{users}} usuarios", + "unlimited_seats": "Ilimitado", + "month": "mes", + "year": "año", + "wantToPayYearly": "Quiero pagar anualmente (cada 12 meses), y obtener un mes gratis por año!" + }, + "Encryption": { + "createEncryptedSession": "Sesión cifrada", + "sessionNotEncrypted": "Esta sesión no está cifrada.", + "sessionEncryptedHaveKeyTooltip": "Esta sesión está cifrada, y la clave se almacena en su navegador. Puede abrir esta sesión sin tener que proporcionar la contraseña de nuevo.", + "sessionEncryptedNoKeyTooltip": "Esta sesión está cifrada, y la clave no se almacena en su navegador. Se le pedirá la clave de descifrado al abrir esta sesión.", + "sessionEncryptedWrongKeyTooltip": "Esta sesión está cifrada y la clave que tiene almacenada no es la clave correcta.", + "newEncryptedSessionWarningTitle": "Esta sesión está cifrada localmente", + "newEncryptedSessionWarningContent": "Es muy importante que guarde la URL completa (que contiene la clave) en algún lugar seguro, o al menos la clave de cifrado: {{key}}. Si pierde esta clave de cifrado, no hay nada que pueda hacerse para recuperar los datos.", + "sessionEncryptionError": "Esta sesión está cifrada, y parece que no tiene la clave de descifrado almacenada localmente. Por favor, utilice el enlace original, incluyendo la clave de descifrado.", + "passwordModalTitle": "Sesión cifrada - Introduzca contraseña", + "passwordModelIncorrect": "La clave de cifrado es incorrecta." + }, + "Private": { + "lockSuccessNotification": "Tu sesión se ha hecho privada con éxito. No se pueden unir nuevos participantes.", + "unlockSuccessNotification": "Tu sesión se ha hecho pública con éxito. Cualquiera puede unirse.", + "lockButton": "Hacer Privado", + "unlockButton": "Hacer público", + "lockDescription": "Está a punto de hacer la sesión privada. Sólo los participantes actuales (listados a continuación) tendrán acceso a esta sesión una vez bloqueado.", + "cancelButton": "Cancelar", + "sessionLockedTitle": "Esta sesión es privada.", + "sessionLockedDescription": "Pídele a su moderador que lo desbloquee para poder unirte. Luego, actualiza esta página.", + "sessionNonProTitle": "Esta sesión sólo es accesible para usuarios Pro", + "sessionNonProDescription": "Esta sesión utiliza características sólo disponibles para usuarios Pro. Por favor, pide al moderador o al titular de la suscripción que te dé una cuenta Pro.", + "sessionIsPublic": "Esta sesión es pública y accesible para cualquier persona.", + "sessionIsPrivate": "Esta sesión es privada y tiene acceso.", + "sessionIsPrivateNoAccess": "Esta sesión es privada, pero no tiene acceso." + }, + "TrialPrompt": { + "allowanceReachedTitle": "Has alcanzado tu franquicia gratuita", + "allowanceReachedDescription": "Para obtener mensajes ilimitados, por favor suscríbase a Retrospected Pro", + "nearEndAllowanceTitle": "Estás cerca del final de tu cuota", + "nearEndAllowanceDescription": "Te quedan alrededor de {{quota}} publicaciones", + "onTrialTitle": "Retrospected Pro - Prueba", + "remainingTrialSentence": "Tienes {{remaining}} restantes en tu periodo de prueba.", + "trialEndedTitle": "Tu Reprobación Pro ha terminado", + "trialEndedSentence": "Suscríbete hoy para recuperar el acceso a las funciones Pro.", + "subscribeNow": "¡Suscríbete ahora!" + }, + "Chat": { + "writeAMessage": "Escribe un mensaje aquí..." + } +} \ No newline at end of file diff --git a/frontend/src/translations/locales/fr-FR.json b/frontend/src/translations/locales/fr-FR.json new file mode 100644 index 000000000..e563bc85a --- /dev/null +++ b/frontend/src/translations/locales/fr-FR.json @@ -0,0 +1,423 @@ +{ + "Header": { + "subtitle": "Un bon moyen de s'exprimer de façon Agile", + "logout": "Déconnexion", + "leave": "Sortir", + "summaryMode": "Mode Résumé", + "account": "Mon compte", + "adminPanel": "Gestion des utilisateurs" + }, + "LanguagePicker": { + "header": "Changez de langue" + }, + "Main": { + "hint": "Vous pouvez inviter d'autres participants en leur envoyant l'URL de cette page" + }, + "Home": { + "welcome": "Bienvenue, {{name}}" + }, + "PreviousGame": { + "createdBy": "Créé par", + "posts_one": "post", + "posts_other": "posts", + "participants_one": "participant", + "participants_other": "participants", + "votes_one": "vote", + "votes_other": "votes", + "actions_one": "action", + "actions_other": "action" + }, + "Column": { + "createGroupTooltip": "Créer un groupe" + }, + "Group": { + "emptyGroupTitle": "Ce groupe est vide", + "emptyGroupContent": "Déplacez un post ici pour le remplir" + }, + "Post": { + "openExtra": "Fonctions supplémentaires", + "closeExtra": "Fermer", + "vote": "vote", + "votes": "votes", + "deleteButton": "Supprimer", + "setActionButton": "Définir une action", + "setGiphyButton": "Choisir une image Giphy", + "noContent": "(Aucun contenu)", + "by": "par", + "upVote": "positif", + "downVote": "négatif", + "voteRemainingMultiple": "Il vous reste {{number}} votes {{type}}s.", + "voteRemainingOne": "Il ne vous reste plus qu'un vote {{type}}, ne le gâchez pas !", + "voteRemainingNone": "Il ne vous reste plus aucun vote {{type}}.", + "toggleGiphyButton": "Montrer/Cacher l'image Giphy" + }, + "Customize": { + "title": "Nouvelle session personalisée", + "votingCategory": "Votes", + "votingCategorySub": "Règles concernant les votes", + "postCategory": "Options des posts", + "postCategorySub": "Règles concernant ce qu'un utilisateur peut faire sur un post", + "customTemplateCategory": "Colonnes personalisées", + "customTemplateCategorySub": "Définir le nombre de colonnes et leurs caractéristiques", + "startButton": "Lancez la session", + "editButton": "Mettre à jour", + "maxUpVotes": "Nb de votes max (positifs)", + "maxUpVotesHelp": "Réglez le nombre de votes positifs maximum qu'un participant peut mettre dans une session", + "maxDownVotes": "Nb de votes max (négatifs)", + "maxDownVotesHelp": "Réglez le nombre de votes négatifs maximum qu'un participant peut mettre dans une session", + "maxPosts": "Nb de posts max", + "maxPostsHelp": "Nombre maximum de posts qu'un participant peut créer par session", + "allowSelfVoting": "Voter pour soi", + "allowSelfVotingHelp": "Autoriser à voter pour ses propres posts", + "allowMultipleVotes": "Votes multiples", + "allowMultipleVotesHelp": "Autoriser à voter plusieurs fois pour le même post", + "allowActions": "Activer les Actions", + "allowActionsHelp": "Permettre ou non le champ 'Action' (suivi) sur chaque message", + "allowAuthorVisible": "Afficher l'auteur", + "allowAuthorVisibleHelp": "Afficher l'auteur du post sur le post lui-même.", + "newPostsFirst": "Nouveaux posts en premier", + "newPostsFirstHelp": "Les nouveaux posts sont ajoutés en haut de chaque colonne", + "allowGiphy": "Activer Giphy", + "allowGiphyHelp": "Autoriser les utilisateurs à ajouter une image Giphy sur n'importe quel post", + "allowGrouping": "Groupes", + "allowGroupingHelp": "Permettre aux utilisateurs de grouper les posts par groupes", + "allowReordering": "Re-organiser", + "allowReorderingHelp": "Permettre aux utilisateurs de réorganiser l'ordre des posts", + "blurCards": "Flouter", + "blurCardsHelp": "Les posts sont floutés, jusqu'à ce qu'un modérateur révèle les posts", + "template": "Règles prédéfinies", + "templateHelp": "Sélectionnez un jeu de colonnes prédéfini", + "numberOfColumns": "Nombre de colonnes", + "numberOfColumnsHelp": "Réglez le nombre de colonnes", + "makeDefaultTemplate": "En faire mes réglages par défaut" + }, + "PostBoard": { + "customQuestion": "Colonne personnalisée", + "notWellQuestion": "Des améliorations ?", + "wellQuestion": "Qu'est-ce qui s'est bien passé ?", + "ideasQuestion": "Une bonne idée à partager ?", + "startQuestion": "Commencer", + "stopQuestion": "Arrêter", + "continueQuestion": "Continuer", + "likedQuestion": "Aimé", + "lackedQuestion": "A manqué", + "learnedQuestion": "Appris", + "longedForQuestion": "A hâte de", + "anchorQuestion": "Ancre", + "boatQuestion": "Bateau", + "islandQuestion": "Île", + "windQuestion": "Vent", + "rockQuestion": "Rocher", + "disconnected": "Vous avez été déconnecté de la session.", + "reconnect": "Se reconnecter", + "notLoggedIn": "Vous n'êtes pas connecté. Vous pouvez regarder cette session en tant que spectateur, mais vous devez vous connecter pour participer.", + "error_action_unauthorised": "Vous n'avez pas la permission de performer cette action.", + "error_cannot_edit_group": "La modification du groupe a échoué.", + "error_cannot_edit_post": "La modification du message a échoué.", + "error_cannot_get_session": "Impossible de charger les données de cette session.", + "error_cannot_register_vote": "Votre vote n'a pas été enregistré.", + "error_cannot_save_group": "Le groupe que vous avez créé n'a pas pu être enregistré correctement.", + "error_cannot_save_post": "Le post que vous avez créé n'a pas pu être enregistré correctement.", + "error_cannot_delete_group": "Le groupe ne peut être supprimé", + "error_cannot_delete_post": "Le post ne peut être supprimé", + "error_cannot_rename_session": "La session ne peut être renommée", + "error_cannot_save_columns": "Les colonnes n'ont pu être enregistrées", + "error_cannot_save_options": "Les options n'ont pu être enregistrées", + "maxPostsReached": "Vous avez atteint le nombre de posts maximum prévu par le modérateur.", + "iAmDone": "J'ai fini !", + "iAmNotDoneYet": "Je n'ai pas encore fini...", + "userIsReady": "{{user}} est prêt !" + }, + "GameMenu": { + "board": "Board", + "summary": "Résumé" + }, + "Template": { + "default": "Par défaut", + "wellNotWell": "Bien / Pas Bien", + "startStopContinue": "Commencer / Arrêter / Continuer", + "fourLs": "Les 4 A", + "sailboat": "Bateau" + }, + "Clients": { + "header": "Participants:", + "joined": "{{users}} connecté.", + "left": "{{users}} déconnecté." + }, + "Join": { + "welcome": "Bienvenue", + "standardTab": { + "header": "Créer", + "text": "Cliquez ci-dessous et commencez à retrospecter:", + "button": "Nouvelle session", + "customizeButton": "Personnaliser" + }, + "optionsTab": { + "header": "Options", + "input": "Donnez un nom à votre session", + "button": "Créer une session personalisée" + }, + "previousTab": { + "header": "Précédentes", + "rejoinButton": "Rejoindre" + } + }, + "AnonymousLogin": { + "namePlaceholder": "Votre nom, ou pseudonyme", + "buttonLabel": "Se connecter", + "header": "Se connecter", + "anonymousAuthHeader": "Identification Anonyme", + "anonymousAuthDescription": "Ceci créera un compte anonyme. Certaines fonctionnalités ne seront pas disponibles.", + "authenticatingWith": "Identification avec", + "or": "ou" + }, + "SocialMediaLogin": { + "header": "OAuth", + "info": "Un service tiers de votre choix va vous permettre de vous authentifier. Aucun mot de passe ne sera stocké." + }, + "AuthCommon": { + "emailField": "Adresse e-mail", + "passwordField": "Mot de passe", + "nameField": "Votre nom (ou pseudo)", + "passwordScoreWords": [ + "faible", + "faible", + "encore un effort", + "suffisant", + "excellent" + ] + }, + "AccountLogin": { + "header": "Mot de Passe", + "loginButton": "Se connecter", + "info": "Connectez-vous avec votre email et votre mot de passe.", + "registerLink": "Pas de compte ? Cliquez ici", + "forgotPasswordLink": "Mot de passe oublié ?", + "errorEmailPasswordIncorrect": "Les identifiants communiqués sont incorrects." + }, + "Register": { + "header": "S'enregistrer", + "info": "Enregistrez un nouveau compte Retrospected.", + "registerButton": "Créer un compte", + "errorAlreadyRegistered": "Désolé, cet email est déjà enregistré", + "errorGeneral": "Une erreur s'est produite lors de la tentative de création de votre compte.", + "messageSuccess": "Merci! Vous devriez recevoir un e-mail sous peu pour valider votre compte.", + "errorInvalidEmail": "Merci d'entrer un email valide" + }, + "ValidateAccount": { + "success": "Votre adresse e-mail a été correctement validée. Je vais vous connecter dans un instant !", + "error": "Une erreur est survenue lors de la validation de votre adresse e-mail.", + "loading": "Nous validons votre e-mail... Merci de votre patience." + }, + "ResetPassword": { + "doneMessage": "C'est fait ! Jetez un œil dans vos e-mails, vous devriez obtenir un lien pour réinitialiser votre mot de passe.", + "header": "Changer de mot de passe", + "resetButton": "Mettre à jour", + "info": "Vous avez oublié votre mot de passe ? Pas de problème, entrez votre email et vous recevrez un email en retour.", + "success": "Votre mot de passe a été mis à jour. Je vais vous connecter dans quelques secondes !", + "error": "Une erreur est survenue lors de la mise à jour de votre mot de passe.", + "loading": "Nous mettons votre mot de passe à jour. Merci de patienter.", + "resetInfo": "Merci de choisir un nouveau mot de passe" + }, + "SummaryBoard": { + "noPosts": "Aucun post à afficher", + "copyAsMarkdown": "Copier le résumé au format Markdown", + "copyAsRichText": "Copier le résumé en texte enrichi", + "copySuccessful": "Vous avez copié le résumé avec succès" + }, + "SessionName": { + "defaultSessionName": "Ma Retrospective" + }, + "Invite": { + "inviteButton": "Inviter", + "dialog": { + "title": "Invitez des participants à votre retrospective", + "text": "Pour inviter des participants à votre session retrospected, envoyez leur le lien suivant", + "copyButton": "Copier" + } + }, + "Generic": { + "ok": "Ok", + "cancel": "Annuler" + }, + "Actions": { + "tooltip": "Créer une action relative à ce commentaire", + "label": "Ajouter une action", + "summaryTitle": "Vos Actions", + "title": "Action" + }, + "DeleteSession": { + "header": "Supprimer \"{{name}}\" ?", + "firstLine": "Effacer une session est irreversible. Tout les posts, groupes, votes et la session elle-même vont être effacés. Les données ne peuvent être récupérée.", + "secondLine": "Êtes-vous certain(e) de vouloir effaçer cette session et son contenu ?", + "yesImSure": "Oui, j'en suis sûr", + "cancel": "Non, je me suis trompé(e)" + }, + "RevealCards": { + "buttonLabel": "Révéler", + "dialogTitle": "Révéler tous les posts", + "dialogContent": "Cela va révéler (déflouter) tout les posts. L'opération n'est pas reversible.", + "confirmButton": "Révéler", + "cancelButton": "Non merci" + }, + "AccountPage": { + "anonymousError": "Les comptes anonymes ne peuvent avoir accès à leur profile (puisque ils n'en ont pas).", + "details": { + "header": "Vos Coordonnées", + "username": "Nom d'utilisateur", + "email": "E-Mail", + "accountType": "Type de compte" + }, + "plan": { + "header": "Votre Accès", + "plan": "Accès", + "youAreOwner": "Vous êtes l'administrateur de cet abonnement. Vous pouvez le gérer via la section ci-dessous.", + "youAreMember": "Vous devez votre accès Pro grâce à l'abonnement d'un tiers." + }, + "subscription": { + "header": "Votre Abonnement", + "manageButton": "Gérer mon abonnement", + "membersEditor": { + "title": "Votre Equipe", + "limitReached": "Vous avez atteint le nombre maximum de membres ({{limit}}) permis par votre abonnement. Vous pouvez passer à l'abonnement Company pour un nombre de collaborateur illimité.", + "info": "Ajouter des addresses emails ci-dessous pour donner un accès Pro à vos collaborateurs (dans la limite de {{limit}} collaborateurs). Appuyez sur Entrée après chaque email." + } + }, + "trial": { + "header": "Votre Periode d'Essai", + "yourTrialWillExpireIn": "Votre période d'essai va se terminer dans {{date}}.", + "subscribe": "S'abonner" + }, + "deleteAccount": { + "title": "RGPD", + "warning": "Vous avez le droit à l'oubli. Cela étant dit, effacer vos données est définitif.", + "deleteData": "Effacer mes données", + "modal": { + "confirm": { + "title": "Êtes-vous absolument certain(e) ?", + "description": "Cette opération n'est pas réversible !", + "confirmation": "Oui, je veux effaçer toutes mes données", + "cancellation": "J'ai changé d'avis !" + }, + "subheader": "Choisir quoi effacer", + "deleteAccount": "Effacer votre compte ainsi que toutes les identités liées à votre email.", + "recommended": "Recommandé", + "deleteSessions": { + "main": "Effacer les sessions (les rétrospectives) que vous avez créées ?", + "selected": "Vos sessions, and toutes les données associées (incluant les posts et votes d'autres personnes) seront éffacées de manière permanente et irréversible.", + "unselected": "Vos sessions seront conservées, et leur auteur deviendra un auteur anonyme." + }, + "deletePosts": { + "main": "Effacer les posts que vous avez écris ?", + "selected": "Vos posts, dans n'importe quelle session, ainsi que les votes associés, seront effacés de manière permanente et irreversible.", + "unselected": "Vos posts seront conservés, mais leur auteur deviendra un compte anonyme." + }, + "deleteVotes": { + "main": "Effacer vos votes ?", + "selected": "Vos votes, dans n'importe quelle session, seront effacés.", + "unselected": "Vos votes seront conservés, et deviendront anonymes." + }, + "deleteAccountButton": "SUPPRIMER VOTRE COMPTE", + "cancelButton": "Annuler" + } + } + }, + "SubscribePage": { + "alertAlreadyPro": "Vous avez déjà un compte Pro, vous n'avez peut-être donc pas besoin d'un abonnement supplémentaire.", + "alertAlreadySubscribed": "Vous avez déjà un abonnement, vous n'avez peut-être donc pas besoin d'un abonnement supplémentaire.", + "currency": { + "title": "Devise", + "description": "Choisissez une devise de facturation.", + "warning": "Votre compte est déjà en {{currency}}, vous ne pouvez donc plus en changer." + }, + "plan": { + "title": "Abonnement", + "description": "Choisissez l'abonnement qui vous convient" + }, + "domain": { + "title": "Nom de domaine", + "description": "Votre abonnement illimité est basé sur le nom de domaine de votre email. Tout utilisateur dont l'email contient ce nom de domaine sera automatiquement un utilisateur Pro.", + "invalidDomain": "Merci d'entrer un nom de domaine valide. Les noms de domaines d'emails gratuits ne sont pas valides." + }, + "subscribe": { + "title": "Payer", + "description": "Vous serez redirigé vers notre partenaire Stripe. Aucune coordonnées bancaire n'est stockée par Retrospected.", + "cannotRegisterWithAnon": "Vous devez être connecté avec un compte OAuth ou Classique (mot de passe) avant de continuer.", + "checkout": "Payer" + } + }, + "SubscribeModal": { + "title": "Abonnement Pro", + "header": "Retrospected Pro", + "description": "Protégez les données de votre entreprise en vous abonnant à Retrospected Pro. Avec Retrospected Pro, bénéficiez des fonctionalités suivantes:", + "features": { + "encryptedSession": { + "title": "Session Cryptées", + "description": "Vos données sont cryptées localement, sur votre navigateur, les rendant impossible à déchiffrer sur le serveur." + }, + "privateSessions": { + "title": "Session Privées", + "description": "Assurez-vous que seules les personnes choisies puissent accéder à votre session." + }, + "unlimitedPosts": { + "title": "Posts illimités", + "description": "Nombre de posts illimité avec Retrospected Pro." + } + }, + "subscribeButton": "S'abonner", + "payButton": "Selectionner", + "cancelButton": "Annuler", + "startTrial": "Essai 30 jours" + }, + "Products": { + "team": "Parfait pour une équipe, vous pouvez sélectioner jusqu'à 20 collègues qui recevront un compte Retrospected Pro.", + "unlimited": "Si vous avez besoin de plus, l'abonnement \"Pro Unlimited\" vous donnera un nombre de compte Pro illimité", + "self-hosted": "Installez Retrospected sur vos serveurs. Gardez le contrôle total de vos données, et profitez des mise-à-jours illimitées.", + "users": "{{users}} utilisateurs", + "unlimited_seats": "Illimité", + "month": "mois", + "year": "an", + "wantToPayYearly": "Je souhaite payer annuellement, et obtenir un mois gratuit par an !" + }, + "Encryption": { + "createEncryptedSession": "Session cryptée", + "sessionNotEncrypted": "Cette session n'est pas cryptée", + "sessionEncryptedHaveKeyTooltip": "Cette session est chiffrée, et la clef est stockée dans votre navigateur. Vous pouvez ouvrir cette session sans avoir à en donner le mot de passe.", + "sessionEncryptedNoKeyTooltip": "Cette session est chiffrée, et la clef n'a pas été trouvée dans votre navigateur. Il vous sera demandé de donner le mot de passe lors de l'ouverture de cette session.", + "sessionEncryptedWrongKeyTooltip": "Cette session est chiffrée, et la clef qui est stockée dans votre navigateur n'est pas la bonne.", + "newEncryptedSessionWarningTitle": "Cette session est chiffrée localement", + "newEncryptedSessionWarningContent": "Il est très important de sauvegarder l'URL complète de cette page (qui contient la clef de chiffrement). Le cas échéant, vous pouvez également sauvegarder la clef elle-même ({{key}}). Si vous perdez cette clef, il vous sera impossible de récupérer vos données.", + "sessionEncryptionError": "Cette session est cryptée, et vous ne semblez pas avoir la clef de chiffrement dans votre navigateur. Merci d'utiliser le lien complet qui vous a été donné lors de la création de cette session.", + "passwordModalTitle": "Session chiffrée - Saisie du mot de passe", + "passwordModelIncorrect": "Le mot de passe (ou clef de chiffrement) est incorrect." + }, + "Private": { + "lockSuccessNotification": "La session a été correctement privatisée. Aucun nouveau participant ne pourra y accéder.", + "unlockSuccessNotification": "La session a été correctement rendue publique.", + "lockButton": "Rendre privée", + "unlockButton": "Rendre publique", + "lockDescription": "Vous êtes sur le point de privatiser la session. Seuls les utilisateurs ayant déjà accédé à cette session (dont la liste s'affiche ci-dessous) pourront accéder à cette session une fois vérouillée.", + "cancelButton": "Annuler", + "sessionLockedTitle": "Cette session est privée.", + "sessionLockedDescription": "Demandez à votre modérateur de la rendre publique pour que vous puissiez la rejoindre. Ensuite, rafraichissez la page.", + "sessionNonProTitle": "Cette session n'est accessible qu'aux utilisateurs Pro.", + "sessionNonProDescription": "Cette session n'est ouverte qu'aux détenteurs d'un compte Retrospected Pro. Vous pouvez demander au modérateur ou au gérant de l'abonnement Pro de vous donner un accès.", + "sessionIsPublic": "Cette session est publique, et accessible à tout le monde.", + "sessionIsPrivate": "Cette session est privée, et vous y avez accès.", + "sessionIsPrivateNoAccess": "Cette session est privée, mais vous n'y avez pas accès." + }, + "TrialPrompt": { + "allowanceReachedTitle": "Vous avez atteint la limite de posts gratuits", + "allowanceReachedDescription": "Inscrivez-vous à Retrospected Pro pour passer en illimité", + "nearEndAllowanceTitle": "Vous approchez la limite de posts gratuits", + "nearEndAllowanceDescription": "Vous avez environ {{quota}} posts restants.", + "onTrialTitle": "Retrospected Pro - Période d'essai", + "remainingTrialSentence": "Vous avez {{remaining}} restant sur votre période d'essai.", + "trialEndedTitle": "Votre période d'essai Retrospected Pro est terminée", + "trialEndedSentence": "Abonnez-vous aujourd'hui pour continuer à bénéficier des avantages de la version Pro.", + "subscribeNow": "Je m'abonne" + }, + "Chat": { + "writeAMessage": "Écrivez un message ici..." + } +} \ No newline at end of file diff --git a/frontend/src/translations/locales/hu-HU.json b/frontend/src/translations/locales/hu-HU.json new file mode 100644 index 000000000..dfe3a8f26 --- /dev/null +++ b/frontend/src/translations/locales/hu-HU.json @@ -0,0 +1,423 @@ +{ + "Header": { + "subtitle": "Panaszkodjunk rendezetten", + "logout": "Kijelentkezés", + "leave": "Távozás", + "summaryMode": "Összesített mód", + "account": "Fiókom", + "adminPanel": "Adminisztrációs panel" + }, + "LanguagePicker": { + "header": "Válassz nyelvet" + }, + "Main": { + "hint": "Ha meg akarsz hívni másokat, másold ki és oszd meg velük az URL-t" + }, + "Home": { + "welcome": "Isten hozott, {{name}}" + }, + "PreviousGame": { + "createdBy": "Készítette", + "posts_one": "hozzászólás", + "posts_other": "hozzászólások", + "participants_one": "résztvevő", + "participants_other": "résztvevők", + "votes_one": "szavazás", + "votes_other": "szavazatokat", + "actions_one": "akció", + "actions_other": "akciók" + }, + "Column": { + "createGroupTooltip": "Hozzon létre egy csoportot a bejegyzések csoportosításához" + }, + "Group": { + "emptyGroupTitle": "Ez egy üres csoport", + "emptyGroupContent": "Helyezzen át egy bejegyzést ide a csoport kitöltéséhez" + }, + "Post": { + "openExtra": "További jellemzők", + "closeExtra": "Bezárás", + "vote": "szavazat", + "votes": "szavazat", + "deleteButton": "törlés", + "setActionButton": "Művelet beállítása", + "setGiphyButton": "Válasszon egy Giphy-képet", + "noContent": "(Ennek a bejegyzésnek nincs tartalma)", + "by": "által", + "upVote": "fel-szavazás", + "downVote": "le-szavazás", + "voteRemainingMultiple": "{{number}} {{type}}mp van hátra.", + "voteRemainingOne": "Már csak egy {{type}} van hátra, számítson rá!", + "voteRemainingNone": "Nem maradt {{type}}.", + "toggleGiphyButton": "Kapcsolja be a Giphy képet" + }, + "Customize": { + "title": "A munkamenet testreszabása", + "votingCategory": "Szavazás", + "votingCategorySub": "Állítsd be a tetszésnyilvánításokra és a nemtetszésekre vonatkozó szabályokat", + "postCategory": "Hozzászólás beállításai", + "postCategorySub": "Állítsa be a szabályokat arra vonatkozóan, hogy a felhasználó mit tehet bejegyzés létrehozásakor vagy megtekintésekor", + "customTemplateCategory": "Oszlop sablon", + "customTemplateCategorySub": "Állítsa be az oszlopok számát és jellemzőit", + "startButton": "Indítsa el a munkamenetet", + "editButton": "Frissítés", + "maxUpVotes": "Max fel-szavazatok", + "maxUpVotesHelp": "Egy felhasználó által leadható „tetszik” szavazatok maximális száma", + "maxDownVotes": "Max le-szavazatok", + "maxDownVotesHelp": "A felhasználó által leadható „nem tetszik” szavazatok maximális száma", + "maxPosts": "Maximum hozzászólások felhasználónként", + "maxPostsHelp": "Egy felhasználó által munkamenetenként létrehozható bejegyzések maximális száma", + "allowSelfVoting": "Önszavazás engedélyezése", + "allowSelfVotingHelp": "Engedélyezi-e a felhasználónak, hogy szavazzon a saját bejegyzésére", + "allowMultipleVotes": "Több szavazat engedélyezése", + "allowMultipleVotesHelp": "Engedélyezi-e, hogy egy felhasználó többször szavazzon ugyanarra a bejegyzésre", + "allowActions": "Műveletek engedélyezése", + "allowActionsHelp": "Engedélyezi-e az „Action” (követés) mezőt az egyes bejegyzéseknél", + "allowAuthorVisible": "Szerző megjelenítése", + "allowAuthorVisibleHelp": "Jelenítse meg a bejegyzés szerzőjét magán a bejegyzésen.", + "newPostsFirst": "Először adj hozzá új bejegyzéseket", + "newPostsFirstHelp": "Az új bejegyzések az oszlop tetején jelennek meg", + "allowGiphy": "Engedélyezze a Giphyt", + "allowGiphyHelp": "Lehetővé teszi a felhasználók számára, hogy Giphy-képet állítsanak be egy bejegyzéshez", + "allowGrouping": "Csoportosítás engedélyezése", + "allowGroupingHelp": "Csoportok létrehozásának engedélyezése a bejegyzések csoportosításához", + "allowReordering": "Újrarendelés engedélyezése", + "allowReorderingHelp": "A bejegyzések átrendezésének engedélyezése fogd és vidd módszerrel", + "blurCards": "Kártyák elmosódása", + "blurCardsHelp": "A kártyák tartalma elmosódik, amíg a moderátor fel nem fedi a tartalmat", + "template": "Sablon", + "templateHelp": "Használjon előre meghatározott oszlopkészletet", + "numberOfColumns": "Oszlopok száma", + "numberOfColumnsHelp": "Állítsa be az oszlopok számát", + "makeDefaultTemplate": "Legyen ez az alapértelmezett sablonom" + }, + "PostBoard": { + "customQuestion": "Egyéni oszlop", + "notWellQuestion": "Mit lehetne jobban csinálni?", + "wellQuestion": "Mit ment jól?", + "ideasQuestion": "Van valami nagyszerű ötleted?", + "startQuestion": "Rajt", + "stopQuestion": "Állj meg", + "continueQuestion": "Folytatni", + "likedQuestion": "tetszett", + "lackedQuestion": "Hiányzik", + "learnedQuestion": "Tanult", + "longedForQuestion": "Vágyott", + "anchorQuestion": "Horgony", + "boatQuestion": "Hajó", + "islandQuestion": "sziget", + "windQuestion": "Szél", + "rockQuestion": "Szikla", + "disconnected": "Lekapcsolták az aktuális munkamenetről.", + "reconnect": "Csatlakozzon újra", + "notLoggedIn": "Nincs bejelentkezve. Ezt az ülést nézőként tekintheti meg, de a részvételhez be kell jelentkeznie.", + "error_action_unauthorised": "Ezt a műveletet nem hajthatja végre.", + "error_cannot_edit_group": "A csoport szerkesztése nem sikerült.", + "error_cannot_edit_post": "A bejegyzés szerkesztése nem sikerült.", + "error_cannot_get_session": "Nem sikerült lekérni a munkamenet adatait. Kérjük, töltse be újra az oldalt.", + "error_cannot_register_vote": "A szavazat regisztrálása nem sikerült.", + "error_cannot_save_group": "A létrehozott csoport nem menthető.", + "error_cannot_save_post": "Az általad létrehozott bejegyzést nem sikerült elmenteni.", + "error_cannot_delete_group": "A csoportot nem sikerült törölni", + "error_cannot_delete_post": "A bejegyzést nem sikerült törölni", + "error_cannot_rename_session": "A munkamenet átnevezése nem sikerült", + "error_cannot_save_columns": "Az oszlopok mentése nem sikerült", + "error_cannot_save_options": "A beállítások mentése nem sikerült", + "maxPostsReached": "Elérted a moderátor által beállított maximális bejegyzések számát.", + "iAmDone": "Kész vagyok!", + "iAmNotDoneYet": "Még nem végeztem...", + "userIsReady": "{{user}} kész!" + }, + "GameMenu": { + "board": "Tábla", + "summary": "Összegzés" + }, + "Template": { + "default": "Alapértelmezett", + "wellNotWell": "Hát / Nem jól", + "startStopContinue": "Indítás / Leállítás / Folytatás", + "fourLs": "Négy Ls", + "sailboat": "Vitorlás" + }, + "Clients": { + "header": "Jelenleg itt van:", + "joined": "{{users}} csatlakozott.", + "left": "{{users}} maradt." + }, + "Join": { + "welcome": "Üdv, ez itt a Retrospected", + "standardTab": { + "header": "Ülés létrehozása", + "text": "Kattints ide a kezdéshez:", + "button": "Új ülés indítása", + "customizeButton": "Testreszab" + }, + "optionsTab": { + "header": "Haladó", + "input": "Adj nevet az ülésnek", + "button": "Ülés létrehozása" + }, + "previousTab": { + "header": "Previous sessions", + "rejoinButton": "Csatlakozzon újra" + } + }, + "AnonymousLogin": { + "namePlaceholder": "Hogy is hívnak? Kérlek írd ide a nevedet", + "buttonLabel": "Kezdjük", + "header": "Belépés", + "anonymousAuthHeader": "Névtelen bejelentkezés", + "anonymousAuthDescription": "Ezzel névtelen fiókot hoz létre. Egyes funkciók nem lesznek elérhetők.", + "authenticatingWith": "Hitelesítés a következővel:", + "or": "vagy" + }, + "SocialMediaLogin": { + "header": "OAuth", + "info": "Ez az Ön által választott harmadik fél szolgáltatót fogja használni az Ön hitelesítésére. Nincs jelszó tárolva." + }, + "AuthCommon": { + "emailField": "Email", + "passwordField": "Jelszó", + "nameField": "Az Ön neve (megjelenítési célból)", + "passwordScoreWords": [ + "gyenge", + "gyenge", + "nem egészen", + "jó", + "erős" + ] + }, + "AccountLogin": { + "header": "Jelszó", + "loginButton": "Belépés", + "info": "Jelentkezzen be e-mail címével és jelszavával.", + "registerLink": "Nem regisztrált? Kattints ide", + "forgotPasswordLink": "Elfelejtette a jelszavát?", + "errorEmailPasswordIncorrect": "A hitelesítési adatai hibásak." + }, + "Register": { + "header": "Regisztráció", + "info": "Szerezzen magának egy Retrospected fiókot!", + "registerButton": "Regisztráció", + "errorAlreadyRegistered": "Ez az e-mail cím már regisztrálva van", + "errorGeneral": "Hiba történt a fiók létrehozása közben.", + "messageSuccess": "Köszönöm! Hamarosan e-mailt kell kapnia fiókja érvényesítéséhez.", + "errorInvalidEmail": "Kérlek létező email címet adj meg" + }, + "ValidateAccount": { + "success": "Az e-mail-címét megfelelően ellenőriztük. Egy pillanat múlva bejelentkezem!", + "error": "Hiba történt az e-mail-cím érvényesítése során.", + "loading": "Ellenőrizzük e-mail-címét. Kérlek várj." + }, + "ResetPassword": { + "doneMessage": "Kész! Nézze meg az e-mailjeit, kapnia kell egy linket a jelszó visszaállításához.", + "header": "Jelszó visszaállítása", + "resetButton": "Jelszó visszaállítása", + "info": "Elfelejtette a jelszavát? Nem probléma. Írja be e-mail címét alább, és kap egy visszaállítási e-mail üzenetet.", + "success": "A jelszava frissítve lett. Egy pillanat múlva bejelentkezem!", + "error": "Hiba történt a jelszó frissítésekor.", + "loading": "Frissítjük jelszavát. Kérlek várj.", + "resetInfo": "Kérjük, adjon meg új jelszót" + }, + "SummaryBoard": { + "noPosts": "Nincsenek megjeleníthető bejegyzések", + "copyAsMarkdown": "Másolja az összefoglalót Markdown néven", + "copyAsRichText": "Másolja ki az összefoglalót Rich Text formátumban", + "copySuccessful": "Sikeresen másolta az összefoglalót a vágólapra" + }, + "SessionName": { + "defaultSessionName": "Retrospektívám" + }, + "Invite": { + "inviteButton": "Meghívás", + "dialog": { + "title": "Hívj meg embereket a retrospektívedre", + "text": "Ha szeretne embereket meghívni az utólagos munkamenetre, egyszerűen küldje el nekik a következő URL-t", + "copyButton": "URL másolása a vágólapra" + } + }, + "Generic": { + "ok": "rendben", + "cancel": "Megszünteti" + }, + "Actions": { + "tooltip": "Hozzon létre egy műveletet az elem hátoldalán", + "label": "Nyissa meg a Művelet panelt", + "summaryTitle": "Az Ön tevékenységei", + "title": "Akció" + }, + "DeleteSession": { + "header": "\"{{name}}\" törlése?", + "firstLine": "A munkamenet törlése visszafordíthatatlan. Törli az összes bejegyzést, szavazatot, csoportot és magát a munkamenetet. Az adatok nem állíthatók vissza.", + "secondLine": "Biztosan törli ezt a munkamenetet és annak összes tartalmát?", + "yesImSure": "Igen biztos vagyok benne", + "cancel": "Nem, sajnálom, hibáztam" + }, + "RevealCards": { + "buttonLabel": "felfed", + "dialogTitle": "Mutasd fel az összes kártyát", + "dialogContent": "Ez mindenki számára felfedi az összes elmosódott kártyát. Ezt nem lehet visszacsinálni.", + "confirmButton": "Fedezzük fel!", + "cancelButton": "Nem köszönöm" + }, + "AccountPage": { + "anonymousError": "Az anonim fiókok nem férhetnek hozzá a profiljukhoz (mert nincs ilyenük).", + "details": { + "header": "Az adataid", + "username": "Felhasználónév", + "email": "Email", + "accountType": "Fiók Típus" + }, + "plan": { + "header": "Az Ön terve", + "plan": "Terv", + "youAreOwner": "Az alábbi előfizetésen keresztül Ön ennek a csomagnak a tulajdonosa.", + "youAreMember": "Valaki más előfizetésén keresztül részt vesz ebben a tervben." + }, + "subscription": { + "header": "Az Ön előfizetése", + "manageButton": "Az előfizetésem kezelése", + "membersEditor": { + "title": "Csapatod", + "limitReached": "Elérted az előfizetésed korlátját ({{limit}} felhasználó, téged is beleértve). Kérjük, távolítsa el a tagokat, vagy frissítsen korlátlan számú vállalati fiókra.", + "info": "Adjon hozzá e-mail-címeket alább, hogy Pro-fiókot biztosítson akár {{limit}} másik kollégának. Minden e-mail cím után nyomja meg az Enter billentyűt." + } + }, + "trial": { + "header": "Az Ön próbatétele", + "yourTrialWillExpireIn": "A próbaidőszak {{date}}-val ér véget.", + "subscribe": "Iratkozz fel most" + }, + "deleteAccount": { + "title": "GDPR", + "warning": "Jogod van ahhoz, hogy elfelejtsenek. Ennek ellenére legyen óvatos a fiók törlésekor. Ezt nem lehet visszacsinálni.", + "deleteData": "Törölje az adataimat", + "modal": { + "confirm": { + "title": "Teljesen biztos vagy benne?", + "description": "Erre nincs visszaút.", + "confirmation": "Igen, törölni akarom az összes adatomat", + "cancellation": "Juttass ki innen" + }, + "subheader": "Válassza ki, mit szeretne törölni", + "deleteAccount": "Törölje fiókját és az e-mailekhez kapcsolódó identitásokat.", + "recommended": "Ajánlott", + "deleteSessions": { + "main": "Töröljük az Ön által létrehozott munkameneteket (retrospektívákat)?", + "selected": "Az Ön munkamenetei és minden adatuk, beleértve mások bejegyzéseit és szavazatait is, véglegesen törlődnek.", + "unselected": "A munkamenetei megmaradnak, és a szerzőjük névtelen felhasználó lesz." + }, + "deletePosts": { + "main": "Töröljük az összes hozzászólást, amit írtál?", + "selected": "Bármely munkamenetben közzétett bejegyzéseid, valamint a hozzájuk kapcsolódó szavazatok és műveletek véglegesen törlődnek.", + "unselected": "A bejegyzéseid megmaradnak, de névtelen felhasználóhoz kapcsolódnak." + }, + "deleteVotes": { + "main": "Töröljük is az összes szavazatát?", + "selected": "Az összes munkamenetben leadott szavazatai véglegesen törlődnek.", + "unselected": "A szavazatait megőrizzük, de névtelen felhasználóhoz kapcsoljuk őket." + }, + "deleteAccountButton": "FIÓK TÖRLÉSE", + "cancelButton": "Megszünteti" + } + } + }, + "SubscribePage": { + "alertAlreadyPro": "Ön már Pro-felhasználó, ezért lehet, hogy nincs szüksége újabb előfizetésre.", + "alertAlreadySubscribed": "Már van előfizetése, ezért lehet, hogy nincs szüksége újabb előfizetésre.", + "currency": { + "title": "Valuta", + "description": "Válassza ki azt a pénznemet, amellyel számlázni szeretne", + "warning": "Fiókja már {{currency}}használatára van beállítva, így a pénznemet többé nem módosíthatja." + }, + "plan": { + "title": "Terv", + "description": "Válassza ki az Ön használati esetének megfelelő tervet!" + }, + "domain": { + "title": "Tartomány", + "description": "Korlátlan előfizetése egy adott domainre vonatkozik. Az e-mail domain minden felhasználója automatikusan Pro-felhasználóvá válik.", + "invalidDomain": "Adjon meg egy érvényes domaint. A domain nem lehet ingyenes vagy eldobható e-mail domain." + }, + "subscribe": { + "title": "Pénztár", + "description": "A fizetésért átirányítjuk partnerünkhöz, a Stripe-hoz", + "cannotRegisterWithAnon": "A folytatáshoz be kell jelentkeznie OAuth- vagy Jelszó-fiókkal.", + "checkout": "Pénztár" + } + }, + "SubscribeModal": { + "title": "Pro előfizetés", + "header": "Retrospected Pro", + "description": "Védje meg cége adatait a Retrospected Pro szolgáltatásra való előfizetéssel. A Retrospected Pro segítségével a következő funkciókat és még sok mást érhet el:", + "features": { + "encryptedSession": { + "title": "Titkosított munkamenetek", + "description": "Adatai titkosítva vannak a böngészőjében, így a Retrospected szerveren lehetetlen a visszafejtés." + }, + "privateSessions": { + "title": "Magánfoglalkozások", + "description": "Győződjön meg arról, hogy csak arra jogosult személyek férhetnek hozzá a munkamenetéhez." + }, + "unlimitedPosts": { + "title": "Korlátlan számú bejegyzés", + "description": "Pro-előfizetéssel korlátlan számú bejegyzést kaphat." + } + }, + "subscribeButton": "Iratkozz fel", + "payButton": "Válassza ki", + "cancelButton": "Megszünteti", + "startTrial": "30 napos próbaverzió" + }, + "Products": { + "team": "Kisebb csapatok számára tökéletes, akár 20 kollégát is kiválaszthat, akiket Pro-fiókra frissítenek.", + "unlimited": "Ha Ön egy nagyobb cég, akkor korlátlan számú Pro-fiókot élvezhet.", + "self-hosted": "Helyszíni visszatekintés, egyszeri díj és korlátlan frissítés. Örökre teljes mértékben kézben tarthatja adatait.", + "users": "{{users}} felhasználó", + "unlimited_seats": "Korlátlan", + "month": "hónap", + "year": "év", + "wantToPayYearly": "Évente szeretnék fizetni (12 havonta), és évente egy hónapot ingyen kapok!" + }, + "Encryption": { + "createEncryptedSession": "Titkosított munkamenet", + "sessionNotEncrypted": "Ez a munkamenet nincs titkosítva.", + "sessionEncryptedHaveKeyTooltip": "Ez a munkamenet titkosított, és a kulcsot a böngésző tárolja. Ezt a munkamenetet a jelszó újbóli megadása nélkül is megnyithatja.", + "sessionEncryptedNoKeyTooltip": "Ez a munkamenet titkosított, és a kulcsot nem tárolja a böngésző. A munkamenet megnyitásakor a rendszer kérni fogja a visszafejtési kulcsot.", + "sessionEncryptedWrongKeyTooltip": "Ez a munkamenet titkosított, és a tárolt kulcs nem a megfelelő kulcs.", + "newEncryptedSessionWarningTitle": "Ez a munkamenet helyileg titkosított", + "newEncryptedSessionWarningContent": "Nagyon fontos, hogy a teljes URL-t (ami tartalmazza a kulcsot) biztonságos helyre mentse, vagy legalább a titkosítási kulcsot: {{key}}. Ha elveszíti ezt a titkosítási kulcsot, nincs mit tenni az adatok visszaállítása érdekében.", + "sessionEncryptionError": "Ez a munkamenet titkosított, és úgy tűnik, hogy nincs helyben tárolva a visszafejtési kulcs. Kérjük, használja az eredeti hivatkozást, beleértve a visszafejtő kulcsot is.", + "passwordModalTitle": "Titkosított munkamenet - Adja meg a jelszót", + "passwordModelIncorrect": "A titkosítási kulcs helytelen." + }, + "Private": { + "lockSuccessNotification": "A munkamenetet sikeresen priváttá tettük. Új résztvevők nem csatlakozhatnak.", + "unlockSuccessNotification": "A munkamenetét sikeresen nyilvánosságra hoztuk. Bárki csatlakozhat.", + "lockButton": "Tedd priváttá", + "unlockButton": "Nyilvánosságra hoz", + "lockDescription": "A munkamenet priváttá tételére készül. Csak a jelenlegi résztvevők (az alábbiakban felsorolva) férhetnek hozzá ehhez a munkamenethez, miután lezárták.", + "cancelButton": "Megszünteti", + "sessionLockedTitle": "Ez a munkamenet privát.", + "sessionLockedDescription": "Kérd meg a moderátort, hogy oldja fel, hogy csatlakozhasson. Ezután frissítse ezt az oldalt.", + "sessionNonProTitle": "Ez a munkamenet csak a Pro felhasználók számára érhető el", + "sessionNonProDescription": "Ez a munkamenet csak a Pro felhasználók számára elérhető funkciókat használja. Kérje meg a moderátort vagy az előfizetés tulajdonosát, hogy adjon Pro-fiókot.", + "sessionIsPublic": "Ez az ülés nyilvános és bárki számára elérhető.", + "sessionIsPrivate": "Ez a munkamenet privát, és Önnek van hozzáférése.", + "sessionIsPrivateNoAccess": "Ez a munkamenet privát, de nincs hozzáférése." + }, + "TrialPrompt": { + "allowanceReachedTitle": "Elérte ingyenes juttatását", + "allowanceReachedDescription": "Ha korlátlan számú bejegyzést szeretne elérni, kérjük, iratkozzon fel a Retrospected Pro szolgáltatásra", + "nearEndAllowanceTitle": "A kvóta végéhez közeledik", + "nearEndAllowanceDescription": "Körülbelül {{quota}} bejegyzésed maradt", + "onTrialTitle": "Retrospected Pro – próbaverzió", + "remainingTrialSentence": "{{remaining}} maradt a próbaidőből.", + "trialEndedTitle": "A Retrospected Pro próbaverziója véget ért", + "trialEndedSentence": "Iratkozzon fel még ma, hogy visszaszerezze a hozzáférést a Pro funkciókhoz.", + "subscribeNow": "Iratkozz fel most!" + }, + "Chat": { + "writeAMessage": "Írj üzenetet ide..." + } +} \ No newline at end of file diff --git a/frontend/src/translations/locales/it-IT.json b/frontend/src/translations/locales/it-IT.json new file mode 100644 index 000000000..a7b04b9ce --- /dev/null +++ b/frontend/src/translations/locales/it-IT.json @@ -0,0 +1,423 @@ +{ + "Header": { + "subtitle": "Un buon modo per esprimersi in Agile", + "logout": "Esci", + "leave": "Abbandona", + "summaryMode": "Modalità sommario", + "account": "Il Mio Account", + "adminPanel": "Pannello Di Amministrazione" + }, + "LanguagePicker": { + "header": "Scegli una lingua" + }, + "Main": { + "hint": "Puoi invitare altre persone a questa sessione copiando ed incollando la URL" + }, + "Home": { + "welcome": "Benvenuto, {{name}}" + }, + "PreviousGame": { + "createdBy": "Creato da", + "posts_one": "post", + "posts_other": "post", + "participants_one": "partecipante", + "participants_other": "partecipanti", + "votes_one": "vota", + "votes_other": "voti", + "actions_one": "azione", + "actions_other": "azioni" + }, + "Column": { + "createGroupTooltip": "Crea un gruppo per raggruppare i post" + }, + "Group": { + "emptyGroupTitle": "Questo gruppo è vuoto", + "emptyGroupContent": "Sposta qui un post per popolare il gruppo" + }, + "Post": { + "openExtra": "Features aggiuntive", + "closeExtra": "Chiudi", + "vote": "voto", + "votes": "voti", + "deleteButton": "Cancella", + "setActionButton": "Imposta azione", + "setGiphyButton": "Scegli una immagine Giphy", + "noContent": "(Questo post non ha contenuto)", + "by": "da", + "upVote": "mi piace", + "downVote": "non mi piace", + "voteRemainingMultiple": "Hai {{number}} {{type}}s rimanenti.", + "voteRemainingOne": "Hai solo un {{type}} rimanente, farlo contare!", + "voteRemainingNone": "Non hai nessun {{type}} rimanente.", + "toggleGiphyButton": "Toggle immagine Giphy" + }, + "Customize": { + "title": "Personalizza il tuo gioco!", + "votingCategory": "Votazione", + "votingCategorySub": "Imposta tutte le regole relative a \"mi piace\" e \"non mi piace\"", + "postCategory": "Impostazioni del Post", + "postCategorySub": "Imposta le azioni che l'utente può fare quando crea o vede un post ", + "customTemplateCategory": "Template di Colonna", + "customTemplateCategorySub": "Imposta il numero di colonne e le sue caratteristiche", + "startButton": "Fai partire il gioco!", + "editButton": "Aggiorna", + "maxUpVotes": "Numero massimo di \"mi piace\"", + "maxUpVotesHelp": "Numero massimo di \"mi piace\" che un utente può mettere", + "maxDownVotes": "Numero massimo di \"non mi piace\"", + "maxDownVotesHelp": "Numero massimo di \"non mi piace\" che un utente può mettere", + "maxPosts": "Max Post per utente", + "maxPostsHelp": "Numero massimo di post che un utente può creare per sessione", + "allowSelfVoting": "Permettere l'auto votazione", + "allowSelfVotingHelp": "Se consentire ad un utente di votare sul proprio post", + "allowMultipleVotes": "Permettere votazioni multiple", + "allowMultipleVotesHelp": "Se consentire a un utente di votare più volte sullo stesso post", + "allowActions": "Permettere Azioni", + "allowActionsHelp": "Se consentire il campo \"Azione\" (follow-up) su ciascun post", + "allowAuthorVisible": "Mostra Autore", + "allowAuthorVisibleHelp": "Mostra l'autore del post nel post stesso.", + "newPostsFirst": "Aggiungi nuovi post prima", + "newPostsFirstHelp": "Nuovi post sono stati aggiunti nella parte superiore della colonna", + "allowGiphy": "Consenti Giphy", + "allowGiphyHelp": "Permetti la creazione di gruppi per raggruppare post", + "allowGrouping": "Consenti il raggruppamento", + "allowGroupingHelp": "Permetti la creazione di gruppi per raggruppare post", + "allowReordering": "Consenti il riordinamento", + "allowReorderingHelp": "Permetti il riordinamento dei post con il trascinamento", + "blurCards": "Sfoca Carte", + "blurCardsHelp": "Il contenuto delle carte è sfocato finché il moderatore non rivela il contenuto", + "template": "Modello", + "templateHelp": "Usa un set di colonne predefinito", + "numberOfColumns": "Numbero di colonne", + "numberOfColumnsHelp": "Imposta il numero di colonne", + "makeDefaultTemplate": "Rendi questo template quello di default" + }, + "PostBoard": { + "customQuestion": "Colonna personalizzata", + "notWellQuestion": "Cosa potrebbe essere migliorato?", + "wellQuestion": "Cosa è andato bene?", + "ideasQuestion": "Qualche idea brillante da condividere?", + "startQuestion": "Inizia", + "stopQuestion": "Ferma", + "continueQuestion": "Continua", + "likedQuestion": "Piaciuto", + "lackedQuestion": "Mancava", + "learnedQuestion": "Imparato", + "longedForQuestion": "Atteso", + "anchorQuestion": "Ancora", + "boatQuestion": "Barca", + "islandQuestion": "Isola", + "windQuestion": "Vento", + "rockQuestion": "Roccia", + "disconnected": "Ti sei disconnesso/a dalla sessione corrente.", + "reconnect": "Riconnesso", + "notLoggedIn": "Non sei autenticato. Puoi assistere a questa sessione come spettatore ma non puoi partecipare", + "error_action_unauthorised": "Non hai i permessi per eseguire questa azione.", + "error_cannot_edit_group": "Modifica del gruppo non riuscita.", + "error_cannot_edit_post": "Modifica del post non riuscita.", + "error_cannot_get_session": "Impossibile ottenere i dati della sessione. Si prega di ricaricare la pagina.", + "error_cannot_register_vote": "Il tuo voto non è stato registrato con successo.", + "error_cannot_save_group": "Il gruppo creato non può essere salvato.", + "error_cannot_save_post": "Il post che hai creato non può essere salvato.", + "error_cannot_delete_group": "Il gruppo non può essere eliminato", + "error_cannot_delete_post": "Il post non può essere eliminato", + "error_cannot_rename_session": "Rinomina della sessione non riuscita", + "error_cannot_save_columns": "Salvataggio colonne non riuscito", + "error_cannot_save_options": "Opzioni di salvataggio fallite", + "maxPostsReached": "Hai raggiunto il numero massimo di post impostati dal moderatore.", + "iAmDone": "Ho finito!", + "iAmNotDoneYet": "Non ho ancora finito...", + "userIsReady": "{{user}} è pronto!" + }, + "GameMenu": { + "board": "Tavola", + "summary": "Sommario" + }, + "Template": { + "default": "Predefinito", + "wellNotWell": "Ok / Non Ok", + "startStopContinue": "Inizia / Stop / Continua", + "fourLs": "Quattro Ls", + "sailboat": "Barca a Vela" + }, + "Clients": { + "header": "Partecipanti:", + "joined": "{{users}} si è unito.", + "left": "{{users}} se n'è andato." + }, + "Join": { + "welcome": "Benvenuto su Retrospected", + "standardTab": { + "header": "Crea", + "text": "Clicca qui sotto per iniziare la retrospective", + "button": "Crea una nuova sessione", + "customizeButton": "Personalizza" + }, + "optionsTab": { + "header": "Opzioni", + "input": "Nome", + "button": "Crea una sessione personalizzata" + }, + "previousTab": { + "header": "Precedente", + "rejoinButton": "Riunisciti" + } + }, + "AnonymousLogin": { + "namePlaceholder": "Benvenuto! Per favore inserisci il tuo nome per continuare", + "buttonLabel": "Iniziamo", + "header": "Accedi", + "anonymousAuthHeader": "Login anonimo", + "anonymousAuthDescription": "Questo creerà un account anonimo, ma non ti permetterà di recuperare le sessioni precedenti.", + "authenticatingWith": "Accedi con", + "or": "oppure" + }, + "SocialMediaLogin": { + "header": "Autenticazione con i Social Media", + "info": "Questo utilizzerà il tuo account per autenticarti e ti permetterà di recuperare tutte le tue sessioni. Nessuna password viene memorizzata." + }, + "AuthCommon": { + "emailField": "E-mail", + "passwordField": "Password", + "nameField": "Il tuo nome (per scopi di visualizzazione)", + "passwordScoreWords": [ + "debole", + "debole", + "non abbastanza", + "buono", + "forte" + ] + }, + "AccountLogin": { + "header": "Password", + "loginButton": "Accedi", + "info": "Accedi con la tua email e password.", + "registerLink": "Non sei registrato? Clicca qui", + "forgotPasswordLink": "Hai dimenticato la password?", + "errorEmailPasswordIncorrect": "Le tue credenziali non sono corrette." + }, + "Register": { + "header": "Registrati", + "info": "Ricevi un account retrospetto!", + "registerButton": "Registrati", + "errorAlreadyRegistered": "Questa email è già registrata", + "errorGeneral": "Si è verificato un errore durante il tentativo di creare il tuo account.", + "messageSuccess": "Grazie! Dovresti ricevere un'email a breve per convalidare il tuo account.", + "errorInvalidEmail": "Inserisci un'email valida" + }, + "ValidateAccount": { + "success": "La tua email è stata correttamente convalidata. Ti accederò tra un secondo!", + "error": "Si è verificato un errore durante la convalida della tua email.", + "loading": "Stiamo convalidando la tua email. Attendere prego." + }, + "ResetPassword": { + "doneMessage": "Fatto! Dai un'occhiata alle tue email, dovresti ottenere un link per reimpostare la password.", + "header": "Reimposta Password", + "resetButton": "Reimposta Password", + "info": "Hai dimenticato la password? Non è un problema. Inserisci la tua email qui sotto e riceverai un prompt di reset email.", + "success": "La tua password è stata aggiornata. Ti accederò tra un secondo!", + "error": "Si è verificato un errore durante l'aggiornamento della password.", + "loading": "Stiamo aggiornando la tua password. Attendere.", + "resetInfo": "Inserisci una nuova password" + }, + "SummaryBoard": { + "noPosts": "Non ci sono post da mostrare", + "copyAsMarkdown": "Copia il sommario come Markdown", + "copyAsRichText": "Copia il sommario come Rich Text", + "copySuccessful": "Hai copiato con successo il testo nella clipboard" + }, + "SessionName": { + "defaultSessionName": "La mia Retrospective" + }, + "Invite": { + "inviteButton": "Invita", + "dialog": { + "title": "Invita persone alla tua retrospective", + "text": "Per invitare persone alla tua sessione di retrospective, devi solo inviare lorola seguente URL", + "copyButton": "Copia la URL nella Clipboard" + } + }, + "Generic": { + "ok": "OK", + "cancel": "Cancella" + }, + "Actions": { + "tooltip": "Crea un'azione dietro a questo item", + "label": "Apri l'Action panel", + "summaryTitle": "Le tue Azioni", + "title": "Azione" + }, + "DeleteSession": { + "header": "Eliminare '{{name}}'?", + "firstLine": "L'eliminazione di una sessione è irreversibile. Eliminerà tutti i post, voti, gruppi e la sessione stessa. I dati non possono essere ripristinati.", + "secondLine": "Sei sicuro di voler eliminare questa sessione e tutti i suoi contenuti?", + "yesImSure": "Sì, sono sicuro", + "cancel": "No, mi dispiace, ho commesso un errore" + }, + "RevealCards": { + "buttonLabel": "Rivela", + "dialogTitle": "Rivela tutte le carte", + "dialogContent": "Questo rivelerà tutte le carte sfocate per tutti. Questo non può essere annullato.", + "confirmButton": "Riveliamo!", + "cancelButton": "No grazie" + }, + "AccountPage": { + "anonymousError": "Gli account anonimi non possono avere accesso al loro profilo (perché non ne hanno uno).", + "details": { + "header": "I Tuoi Dettagli", + "username": "Username", + "email": "Email", + "accountType": "Tipo Di Account" + }, + "plan": { + "header": "Il Tuo Piano", + "plan": "Piano", + "youAreOwner": "Sei il proprietario di questo piano, tramite l'abbonamento qui sotto.", + "youAreMember": "Sei su questo piano attraverso l'abbonamento di qualcun altro." + }, + "subscription": { + "header": "Il Tuo Abbonamento", + "manageButton": "Gestisci il mio abbonamento", + "membersEditor": { + "title": "La Tua Squadra", + "limitReached": "Hai raggiunto il limite del tuo abbonamento ({{limit}} utenti, incluso te stesso). Rimuovi i membri o aggiorna a un account illimitato dell'azienda.", + "info": "Aggiungi email qui sotto per concedere account Pro fino a {{limit}} altri colleghi. Premi Invio dopo ogni indirizzo email." + } + }, + "trial": { + "header": "La Tua Prova", + "yourTrialWillExpireIn": "La tua prova terminerà tra {{date}}.", + "subscribe": "Iscriviti ora" + }, + "deleteAccount": { + "title": "GDPR", + "warning": "Hai il diritto di essere dimenticato. Detto questo, fai attenzione quando elimini il tuo account. Questo non può essere annullato.", + "deleteData": "Elimina i miei dati", + "modal": { + "confirm": { + "title": "Sei assolutamente sicuro?", + "description": "Su questo punto non si può tornare indietro.", + "confirmation": "Sì Voglio eliminare tutti i miei dati", + "cancellation": "Portami fuori da qui" + }, + "subheader": "Scegli cosa eliminare", + "deleteAccount": "Elimina il tuo account e tutte le identità collegate alla tua email.", + "recommended": "Consigliato", + "deleteSessions": { + "main": "Dovremmo eliminare le sessioni (retrospettive) che hai creato?", + "selected": "Le sessioni e tutti i loro dati, compresi i post e i voti di altre persone, verranno eliminati in modo permanente.", + "unselected": "Le sessioni saranno mantenute e il loro autore diventerà un utente anonimo." + }, + "deletePosts": { + "main": "Dovremmo eliminare tutti i post che hai scritto?", + "selected": "I tuoi post, in qualsiasi sessione, e i loro voti associati e le azioni saranno eliminati definitivamente.", + "unselected": "I tuoi post saranno mantenuti, ma saranno associati con un utente anonimo." + }, + "deleteVotes": { + "main": "Dovremmo anche cancellare tutte le votazioni?", + "selected": "I tuoi voti, in tutte le sessioni verranno eliminati definitivamente.", + "unselected": "I tuoi voti saranno mantenuti, ma saranno associati con un utente anonimo." + }, + "deleteAccountButton": "ELIMINA IL TUO ACCOUNT", + "cancelButton": "Annulla" + } + } + }, + "SubscribePage": { + "alertAlreadyPro": "Sei già un utente Pro, quindi potresti non aver bisogno di un altro abbonamento.", + "alertAlreadySubscribed": "Hai già un abbonamento, quindi potrebbe non essere necessario un altro abbonamento.", + "currency": { + "title": "Valuta", + "description": "Scegli una valuta con cui ti piacerebbe essere addebitato", + "warning": "Il tuo account è già impostato per utilizzare {{currency}}, quindi non puoi più cambiare la valuta." + }, + "plan": { + "title": "Piano", + "description": "Scegli il piano che si adatta al tuo caso d'uso!" + }, + "domain": { + "title": "Dominio", + "description": "Il tuo abbonamento illimitato si applica a un determinato dominio. Qualsiasi utente con questo dominio di posta elettronica diventerà automaticamente un utente Pro.", + "invalidDomain": "Fornisci un dominio valido. Il dominio non può essere un dominio email gratuito o usa e getta." + }, + "subscribe": { + "title": "Checkout", + "description": "Sarai reindirizzato al nostro partner, Stripe, per il pagamento", + "cannotRegisterWithAnon": "Devi essere connesso con un account OAuth o Password per continuare.", + "checkout": "Checkout" + } + }, + "SubscribeModal": { + "title": "Abbonamento Pro", + "header": "Retrospected Pro", + "description": "Proteggi i dati della tua azienda sottoscrivendo Pro. Con Pro, ottieni le seguenti funzionalità e molto altro ancora:", + "features": { + "encryptedSession": { + "title": "Sessioni Crittografate", + "description": "I tuoi dati sono crittografati nel tuo browser, rendendo impossibile qualsiasi decodifica sul server Retrospetto." + }, + "privateSessions": { + "title": "Sessioni Private", + "description": "Assicurati che solo le persone autorizzate possano accedere alla sessione." + }, + "unlimitedPosts": { + "title": "Post Illimitati", + "description": "Con un abbonamento Pro, ottieni messaggi illimitati." + } + }, + "subscribeButton": "Abbonati", + "payButton": "Seleziona", + "cancelButton": "Annulla", + "startTrial": "Prova di 30 giorni" + }, + "Products": { + "team": "Perfetto per i team più piccoli, è possibile selezionare fino a 20 colleghi che saranno aggiornati a un account Pro.", + "unlimited": "Se siete una società più grande, potrete godere di un numero illimitato di account Pro.", + "self-hosted": "Retrospected on premise, un-time fee and unlimited updates. Keep total control of your data, for ever.", + "users": "{{users}} utenti", + "unlimited_seats": "Illimitato", + "month": "mese", + "year": "anno", + "wantToPayYearly": "Voglio pagare annualmente (ogni 12 mesi), e ottenere un mese gratis all'anno!" + }, + "Encryption": { + "createEncryptedSession": "Sessione Criptata", + "sessionNotEncrypted": "Questa sessione non è cifrata.", + "sessionEncryptedHaveKeyTooltip": "Questa sessione è crittografata e la chiave è memorizzata nel tuo browser. Puoi aprire questa sessione senza dover fornire nuovamente la password.", + "sessionEncryptedNoKeyTooltip": "Questa sessione è crittografata e la chiave non è memorizzata nel tuo browser. Ti verrà chiesta la chiave di decrittazione quando apri questa sessione.", + "sessionEncryptedWrongKeyTooltip": "Questa sessione è crittografata e la chiave memorizzata non è la chiave corretta.", + "newEncryptedSessionWarningTitle": "Questa sessione è cifrata localmente", + "newEncryptedSessionWarningContent": "E 'molto importante per voi di salvare l'URL completo (che contiene la chiave) in qualche luogo sicuro, o almeno la chiave di crittografia: {{key}}. Se perdi questa chiave di crittografia, non c'è nulla che possa essere fatto per recuperare i dati.", + "sessionEncryptionError": "Questa sessione è crittografata e non sembra che tu abbia la chiave di decodifica memorizzata localmente. Si prega di utilizzare il link originale, inclusa la chiave di decrittazione.", + "passwordModalTitle": "Sessione Criptata - Inserire La Password", + "passwordModelIncorrect": "La chiave di crittografia non è corretta." + }, + "Private": { + "lockSuccessNotification": "La sessione è stata resa privata con successo. Nessun nuovo partecipante può partecipare.", + "unlockSuccessNotification": "La tua sessione è stata resa pubblica con successo. Chiunque può partecipare.", + "lockButton": "Rendi Privato", + "unlockButton": "Rendi Pubblico", + "lockDescription": "Stai per rendere la sessione privata. Solo i partecipanti attuali (elencati di seguito) avranno accesso a questa sessione una volta bloccato.", + "cancelButton": "Annulla", + "sessionLockedTitle": "Questa sessione è privata.", + "sessionLockedDescription": "Chiedi al suo moderatore di sbloccarlo in modo che tu possa entrare. Quindi, aggiorna questa pagina.", + "sessionNonProTitle": "Questa sessione è accessibile solo agli utenti Pro", + "sessionNonProDescription": "Questa sessione utilizza funzionalità disponibili solo per gli utenti Pro. Si prega di chiedere al moderatore o titolare di abbonamento di fornire un account Pro.", + "sessionIsPublic": "Questa sessione è pubblica e accessibile a chiunque.", + "sessionIsPrivate": "Questa sessione è privata e hai accesso.", + "sessionIsPrivateNoAccess": "Questa sessione è privata, ma non hai accesso." + }, + "TrialPrompt": { + "allowanceReachedTitle": "Hai raggiunto il tuo assegno gratuito", + "allowanceReachedDescription": "Per ottenere post illimitati, ti preghiamo di iscriverti a Retrospected Pro", + "nearEndAllowanceTitle": "Stai avvicinando la fine della tua quota", + "nearEndAllowanceDescription": "Hai circa {{quota}} post rimasti", + "onTrialTitle": "Retrospected Pro - Prova", + "remainingTrialSentence": "Hai {{remaining}} rimanenti nella tua prova.", + "trialEndedTitle": "La tua Prova Pro Retrospected è terminata", + "trialEndedSentence": "Iscriviti oggi per recuperare l'accesso alle funzionalità Pro.", + "subscribeNow": "Iscriviti ora!" + }, + "Chat": { + "writeAMessage": "Scrivi un messaggio qui..." + } +} \ No newline at end of file diff --git a/frontend/src/translations/locales/ja-JP.json b/frontend/src/translations/locales/ja-JP.json new file mode 100644 index 000000000..0eaf0b003 --- /dev/null +++ b/frontend/src/translations/locales/ja-JP.json @@ -0,0 +1,423 @@ +{ + "Header": { + "subtitle": "A good way of ranting in an Agile way", + "logout": "ログアウト", + "leave": "退室", + "summaryMode": "要約モード", + "account": "マイアカウント", + "adminPanel": "管理パネル" + }, + "LanguagePicker": { + "header": "言語を選択" + }, + "Main": { + "hint": "URLを共有すれば新たな参加者を本セッションに招待できます" + }, + "Home": { + "welcome": "ようこそ、 {{name}}" + }, + "PreviousGame": { + "createdBy": "作成者:", + "posts_one": "投稿", + "posts_other": "投稿", + "participants_one": "参加者", + "participants_other": "参加者", + "votes_one": "投票", + "votes_other": "投票", + "actions_one": "アクション", + "actions_other": "アクション" + }, + "Column": { + "createGroupTooltip": "一緒に投稿をグループ化するグループを作成" + }, + "Group": { + "emptyGroupTitle": "これは空のグループです", + "emptyGroupContent": "このグループを埋めるには、ここに投稿を移動してください" + }, + "Post": { + "openExtra": "その他の機能", + "closeExtra": "閉じる", + "vote": "投票", + "votes": "表決", + "deleteButton": "削除", + "setActionButton": "アクションを設定", + "setGiphyButton": "Giphy画像を選択", + "noContent": "(項目が空です)", + "by": "作成者:", + "upVote": "up-vote", + "downVote": "downvote", + "voteRemainingMultiple": "残り {{number}} {{type}}秒です。", + "voteRemainingOne": "残り {{type}} は1つです。カウントしてください!", + "voteRemainingNone": "残り {{type}} はありません。", + "toggleGiphyButton": "Giphy画像の切り替え" + }, + "Customize": { + "title": "セッションをカスタマイズ", + "votingCategory": "投票", + "votingCategorySub": "「いいね」と「嫌い」に関するルールを設定", + "postCategory": "投稿設定", + "postCategorySub": "投稿を作成または表示する際にユーザができることに関するルールを設定します", + "customTemplateCategory": "列テンプレート", + "customTemplateCategorySub": "列数とその特性を設定します", + "startButton": "セッションを開始", + "editButton": "更新", + "maxUpVotes": "最大投票数", + "maxUpVotesHelp": "Maximum number of 'likes' vote which user is allowed to cast.", + "maxDownVotes": "投票の最大数", + "maxDownVotesHelp": "ユーザーがキャストできる「嫌い」票の最大数", + "maxPosts": "ユーザーあたりの最大投稿数", + "maxPostsHelp": "Maximum number of posts a user can create per session", + "allowSelfVoting": "自己投票を許可する", + "allowSelfVotingHelp": "ユーザーが自分の投稿に投票できるようにするかどうか", + "allowMultipleVotes": "複数の投票を許可する", + "allowMultipleVotesHelp": "ユーザーが同じ投稿に複数回投票できるようにするか", + "allowActions": "アクションを許可する", + "allowActionsHelp": "各投稿の「アクション」フィールドを許可するかどうか", + "allowAuthorVisible": "投稿者を表示", + "allowAuthorVisibleHelp": "投稿者を投稿自体に表示します。", + "newPostsFirst": "新しい投稿を先に追加", + "newPostsFirstHelp": "新しい投稿が列の上部に追加されます", + "allowGiphy": "Giphyを許可する", + "allowGiphyHelp": "ユーザーが投稿に対してGiphy画像を設定できるようにする", + "allowGrouping": "グループ化を許可", + "allowGroupingHelp": "投稿をグループ化するグループの作成を許可する", + "allowReordering": "並べ替えを許可", + "allowReorderingHelp": "ドラッグ&ドロップで投稿の並べ替えを許可する", + "blurCards": "ぼかしカード", + "blurCardsHelp": "モデレーターがコンテンツを表示するまでカードの内容がぼかしています", + "template": "テンプレート", + "templateHelp": "あらかじめ定義された列のセットを使用", + "numberOfColumns": "列数", + "numberOfColumnsHelp": "列数を設定", + "makeDefaultTemplate": "これをデフォルトのテンプレートにする" + }, + "PostBoard": { + "customQuestion": "カスタム列", + "notWellQuestion": "改善できること", + "wellQuestion": "良かったこと", + "ideasQuestion": "共有したいアイディア", + "startQuestion": "開始", + "stopQuestion": "停止", + "continueQuestion": "続ける", + "likedQuestion": "いいね!", + "lackedQuestion": "不足しています", + "learnedQuestion": "学びました", + "longedForQuestion": "Longed For", + "anchorQuestion": "アンカー", + "boatQuestion": "ボート", + "islandQuestion": "島", + "windQuestion": "風", + "rockQuestion": "岩", + "disconnected": "現在のセッションから切断されました。", + "reconnect": "再接続", + "notLoggedIn": "ログインしていません。このセッションは観戦者として表示できますが、参加するにはログインする必要があります。", + "error_action_unauthorised": "この操作を実行する権限がありません。", + "error_cannot_edit_group": "グループの編集に失敗しました。", + "error_cannot_edit_post": "投稿の編集に失敗しました。", + "error_cannot_get_session": "セッションデータを取得できませんでした。ページを再読み込みしてください。", + "error_cannot_register_vote": "投票は正常に登録されませんでした。", + "error_cannot_save_group": "作成したグループを保存できませんでした。", + "error_cannot_save_post": "作成した投稿を保存できませんでした。", + "error_cannot_delete_group": "グループを削除できませんでした", + "error_cannot_delete_post": "投稿を削除できませんでした", + "error_cannot_rename_session": "セッションの名前を変更できませんでした", + "error_cannot_save_columns": "列の保存に失敗しました", + "error_cannot_save_options": "オプションの保存に失敗しました", + "maxPostsReached": "モデレーターが設定した投稿の最大数に達しました。", + "iAmDone": "終わりました!", + "iAmNotDoneYet": "まだ完了していません...", + "userIsReady": "{{user}} の準備ができました!" + }, + "GameMenu": { + "board": "ボード", + "summary": "Summary" + }, + "Template": { + "default": "デフォルト", + "wellNotWell": "よくない/よくない", + "startStopContinue": "開始 / 停止 / 続ける", + "fourLs": "4 Ls", + "sailboat": "帆船" + }, + "Clients": { + "header": "現在の参加者", + "joined": "{{users}} が参加しました。", + "left": "{{users}} が残りました。" + }, + "Join": { + "welcome": "Retrospectedへようこそ", + "standardTab": { + "header": "作成", + "text": "セッションを作成してレトロスペクティブをはじめる", + "button": "新しいセッションを作成する", + "customizeButton": "カスタマイズ" + }, + "optionsTab": { + "header": "設定", + "input": "名前", + "button": "カスタムセッショを作成する" + }, + "previousTab": { + "header": "以前のセッション", + "rejoinButton": "再開" + } + }, + "AnonymousLogin": { + "namePlaceholder": "名前を入力", + "buttonLabel": "スタート", + "header": "ログイン", + "anonymousAuthHeader": "匿名でログイン", + "anonymousAuthDescription": "これは匿名アカウントを作成します。いくつかの機能は利用できません。", + "authenticatingWith": "認証中", + "or": "または" + }, + "SocialMediaLogin": { + "header": "OAuth", + "info": "認証を選択した第三者プロバイダーを使用します。パスワードは保存されません。" + }, + "AuthCommon": { + "emailField": "電子メール", + "passwordField": "パスワード", + "nameField": "あなたの名前 (表示目的のため)", + "passwordScoreWords": [ + "弱い", + "弱い", + "そうではありません", + "良い", + "強い" + ] + }, + "AccountLogin": { + "header": "パスワード", + "loginButton": "ログイン", + "info": "メールアドレスとパスワードでログインします。", + "registerLink": "登録されていませんか?ここをクリックしてください", + "forgotPasswordLink": "パスワードをお忘れですか?", + "errorEmailPasswordIncorrect": "資格情報が正しくありません。" + }, + "Register": { + "header": "登録", + "info": "レトロスペクティブなアカウントを手に入れよう!", + "registerButton": "登録", + "errorAlreadyRegistered": "このメールアドレスは既に登録されています", + "errorGeneral": "アカウントの作成中にエラーが発生しました。", + "messageSuccess": "ありがとうございます!あなたのアカウントを認証するために間もなくメールが届きます。", + "errorInvalidEmail": "有効なメールアドレスを入力してください" + }, + "ValidateAccount": { + "success": "あなたのメールアドレスは正しく認証されました。すぐにログインします!", + "error": "メールアドレスの検証中にエラーが発生しました。", + "loading": "メールアドレスを認証中です。しばらくお待ちください。" + }, + "ResetPassword": { + "doneMessage": "完了しました!メールを確認してください。パスワードをリセットするためのリンクが表示されます。", + "header": "パスワードのリセット", + "resetButton": "パスワードのリセット", + "info": "パスワードをお忘れですか?問題ありません。下にメールアドレスを入力すると、リセットのメールが表示されます。", + "success": "パスワードが更新されました。すぐにログインします!", + "error": "パスワードの更新中にエラーが発生しました。", + "loading": "パスワードを更新中です。しばらくお待ちください。", + "resetInfo": "新しいパスワードを入力してください" + }, + "SummaryBoard": { + "noPosts": "表示する項目がありません", + "copyAsMarkdown": "概要をマークダウンとしてコピー", + "copyAsRichText": "要約をリッチテキストとしてコピー", + "copySuccessful": "クリップボードにサマリーをコピーしました" + }, + "SessionName": { + "defaultSessionName": "新しいレトロスペクティブ" + }, + "Invite": { + "inviteButton": "招待", + "dialog": { + "title": "レトロスペクティブに招待する", + "text": "下記のURLを共有して本セッションに招待できます", + "copyButton": "URLをクリップボードにコピー" + } + }, + "Generic": { + "ok": "OK", + "cancel": "キャンセル" + }, + "Actions": { + "tooltip": "アクションを作成する", + "label": "アクションパネルを開く", + "summaryTitle": "あなたの行動", + "title": "アクション" + }, + "DeleteSession": { + "header": "'{{name}}' を削除していますか?", + "firstLine": "セッションの削除は元に戻すことができません。すべての投稿、投票、グループ、およびセッション自体を削除します。データは復元できません。", + "secondLine": "このセッションとすべてのコンテンツを削除してもよろしいですか?", + "yesImSure": "はい、確信しています", + "cancel": "いいえ、申し訳ありませんが、間違いを犯しました" + }, + "RevealCards": { + "buttonLabel": "表示する", + "dialogTitle": "すべてのカードを表示", + "dialogContent": "すべてのぼやけたカードが表示されます。元に戻すことはできません。", + "confirmButton": "明らかにしましょう!", + "cancelButton": "いいえ結構です" + }, + "AccountPage": { + "anonymousError": "匿名のアカウントはプロフィールへのアクセス権を持つことはできません(そのアカウントがないので)", + "details": { + "header": "詳細", + "username": "ユーザー名", + "email": "Eメールアドレス", + "accountType": "アカウントの種類" + }, + "plan": { + "header": "あなたのプラン", + "plan": "プラン", + "youAreOwner": "あなたは以下のサブスクリプションを通じて、このプランの所有者です。", + "youAreMember": "あなたは他人のサブスクリプションを通じてこのプランにいます。" + }, + "subscription": { + "header": "あなたのサブスクリプション", + "manageButton": "サブスクリプションの管理", + "membersEditor": { + "title": "あなたのチーム", + "limitReached": "サブスクリプションの上限に達しました(自分を含む{{limit}} ユーザー)。メンバーを削除するか、無制限の会社アカウントにアップグレードしてください。", + "info": "Proアカウントに他の {{limit}} 人の同僚を許可するには、以下のメールを追加してください。各メールアドレスの後にEnterを押します。" + } + }, + "trial": { + "header": "あなたのトライアル", + "yourTrialWillExpireIn": "試用期間は {{date}}で終了します。", + "subscribe": "今すぐ購読する" + }, + "deleteAccount": { + "title": "GDPR", + "warning": "あなたには忘れられる権利があります。アカウントを削除する際は注意してください。元に戻すことはできません。", + "deleteData": "データを削除する", + "modal": { + "confirm": { + "title": "本当によろしいですか?", + "description": "これには後戻りはできない。", + "confirmation": "はい、すべてのデータを削除します", + "cancellation": "ここから出してください" + }, + "subheader": "削除するものを選択してください", + "deleteAccount": "アカウントとメールにリンクされているIDを削除します。", + "recommended": "Recommended", + "deleteSessions": { + "main": "作成したセッション(遡及)を削除しますか?", + "selected": "セッションと他の人の投稿や投票を含むすべてのデータは完全に削除されます。", + "unselected": "セッションは保持され、その著者は匿名ユーザーになります。" + }, + "deletePosts": { + "main": "投稿したすべての投稿を削除しますか?", + "selected": "投稿、セッション、および関連する投票およびアクションは完全に削除されます。", + "unselected": "あなたの投稿は保持されますが、匿名ユーザーに関連付けられます。" + }, + "deleteVotes": { + "main": "すべての投票も削除しますか?", + "selected": "投票はすべてのセッションで完全に削除されます。", + "unselected": "投票は保持されますが、匿名ユーザーに関連付けられます。" + }, + "deleteAccountButton": "アカウントを削除する", + "cancelButton": "キャンセル" + } + } + }, + "SubscribePage": { + "alertAlreadyPro": "あなたはすでにProユーザーなので、別のサブスクリプションは必要ないかもしれません。", + "alertAlreadySubscribed": "既にサブスクリプションがありますので、別のサブスクリプションは必要ないかもしれません。", + "currency": { + "title": "通貨", + "description": "請求先の通貨を選択してください", + "warning": "あなたのアカウントは既に {{currency}}を使用するように設定されているため、通貨を変更することはできません。" + }, + "plan": { + "title": "プラン", + "description": "あなたのユースケースに合ったプランを選択してください!" + }, + "domain": { + "title": "ドメイン", + "description": "無制限のサブスクリプションは、特定のドメインに適用されます。このメールドメインを持つすべてのユーザーは、自動的にプロユーザーになります。", + "invalidDomain": "有効なドメインを入力してください。ドメインは無料または使い捨てのメールドメインにすることはできません。" + }, + "subscribe": { + "title": "チェックアウト", + "description": "支払いのために、パートナーのStripeにリダイレクトされます。", + "cannotRegisterWithAnon": "続行するには、OAuth アカウントまたはパスワードアカウントでログインする必要があります。", + "checkout": "チェックアウト" + } + }, + "SubscribeModal": { + "title": "Proサブスクリプション", + "header": "Retrospected Pro", + "description": "Retrospected Proに登録することで、会社のデータを保護します。Retrospected Proでは、以下の機能を利用できます。", + "features": { + "encryptedSession": { + "title": "暗号化されたセッション", + "description": "あなたのデータはブラウザで暗号化されているため、Retrospectedサーバーでは復号できません。" + }, + "privateSessions": { + "title": "プライベートセッション", + "description": "承認された人だけがセッションにアクセスできることを確認してください。" + }, + "unlimitedPosts": { + "title": "無制限の投稿", + "description": "Proサブスクリプションでは、無制限の投稿を取得します。" + } + }, + "subscribeButton": "購読する", + "payButton": "選択", + "cancelButton": "キャンセル", + "startTrial": "30日間のトライアル" + }, + "Products": { + "team": "小規模なチームに最適な場合は、Proアカウントにアップグレードされる最大20人の同僚を選択できます。", + "unlimited": "あなたがより大きな会社であれば、あなたは無制限のProアカウントを楽しむことができます。", + "self-hosted": "オンプレミス、一回限りの料金、無制限のアップデートで、常にデータを完全に制御し続けましょう。", + "users": "{{users}} ユーザー", + "unlimited_seats": "無制限です", + "month": "月", + "year": "年", + "wantToPayYearly": "私は毎年(12ヶ月ごと)を支払い、毎年1ヶ月無料にしたいと思います!" + }, + "Encryption": { + "createEncryptedSession": "暗号化セッション", + "sessionNotEncrypted": "このセッションは暗号化されていません。", + "sessionEncryptedHaveKeyTooltip": "このセッションは暗号化されており、キーはブラウザに保存されます。再度パスワードを入力することなく、このセッションを開くことができます。", + "sessionEncryptedNoKeyTooltip": "このセッションは暗号化されており、キーはブラウザに保存されていません。このセッションを開くときに復号キーを求められます。", + "sessionEncryptedWrongKeyTooltip": "このセッションは暗号化されており、保存したキーは正しいキーではありません。", + "newEncryptedSessionWarningTitle": "このセッションはローカルで暗号化されています", + "newEncryptedSessionWarningContent": "完全な URL (キーを含む) を安全な場所に保存することは非常に重要です。 または、暗号化キー: {{key}}。 この暗号化キーを失った場合、データを取得するためにできることは何もありません。", + "sessionEncryptionError": "このセッションは暗号化されており、ローカルに復号キーが保存されていないようです。復号キーを含む元のリンクを使用してください。", + "passwordModalTitle": "暗号化されたセッション - パスワードを入力", + "passwordModelIncorrect": "暗号化キーが正しくありません。" + }, + "Private": { + "lockSuccessNotification": "セッションがプライベートになりました。新しい参加者は参加できません。", + "unlockSuccessNotification": "セッションが公開されました。誰でも参加できます。", + "lockButton": "プライベートにする", + "unlockButton": "公開する", + "lockDescription": "セッションを非公開にしようとしています。ロックされると、現在の参加者(以下のリスト)だけがこのセッションへのアクセスを許可されます。", + "cancelButton": "キャンセル", + "sessionLockedTitle": "このセッションはプライベートです。", + "sessionLockedDescription": "参加できるようにモデレータにロックを解除するよう依頼してください。その後、このページを更新してください。", + "sessionNonProTitle": "このセッションはProユーザーのみアクセス可能です", + "sessionNonProDescription": "このセッションでは、Proユーザーのみが利用できる機能を使用します。Proアカウントを提供するには、モデレータまたはサブスクリプション所有者に問い合わせてください。", + "sessionIsPublic": "このセッションは公開され、誰でもアクセスできます。", + "sessionIsPrivate": "このセッションはプライベートでアクセスできます。", + "sessionIsPrivateNoAccess": "このセッションはプライベートですが、アクセスできません。" + }, + "TrialPrompt": { + "allowanceReachedTitle": "無料手当に達しました", + "allowanceReachedDescription": "無制限の投稿を取得するには、Retrospected Pro に登録してください", + "nearEndAllowanceTitle": "割り当ての終わりに近づいています", + "nearEndAllowanceDescription": "残り {{quota}} 件の投稿があります", + "onTrialTitle": "Retrospected Pro - トライアル", + "remainingTrialSentence": "試用版に {{remaining}} が残っています。", + "trialEndedTitle": "Retrospected Pro Trial は終了しました", + "trialEndedSentence": "今すぐ購読して、Pro機能へのアクセスを取り戻しましょう。", + "subscribeNow": "今すぐ購読!" + }, + "Chat": { + "writeAMessage": "ここにメッセージを書いてください" + } +} \ No newline at end of file diff --git a/frontend/src/translations/locales/nl-NL.json b/frontend/src/translations/locales/nl-NL.json new file mode 100644 index 000000000..917d7e87b --- /dev/null +++ b/frontend/src/translations/locales/nl-NL.json @@ -0,0 +1,423 @@ +{ + "Header": { + "subtitle": "Een goede manier om in een gestructureerde manier te tieren", + "logout": "Afmelden", + "leave": "Verlaten", + "summaryMode": "Samenvatting", + "account": "Mijn account", + "adminPanel": "Beheer paneel" + }, + "LanguagePicker": { + "header": "Kies een taal" + }, + "Main": { + "hint": "Je kan anderen uitnodigen voor deze sessie door de URL te kopiëren en te plakken" + }, + "Home": { + "welcome": "Welkom, {{name}}" + }, + "PreviousGame": { + "createdBy": "Aangemaakt door", + "posts_one": "bericht", + "posts_other": "berichten", + "participants_one": "deelnemer", + "participants_other": "deelnemers", + "votes_one": "stemmen", + "votes_other": "Stemmen", + "actions_one": "actie", + "actions_other": "acties" + }, + "Column": { + "createGroupTooltip": "Creeër een groep om retropunten te bundelen" + }, + "Group": { + "emptyGroupTitle": "Dit is een lege groep", + "emptyGroupContent": "Verplaats een retropunt hierheen om deze groep te vullen" + }, + "Post": { + "openExtra": "Extra features", + "closeExtra": "Sluiten", + "vote": "Stem", + "votes": "Stemmen", + "deleteButton": "Verwijderen", + "setActionButton": "Instellen actie", + "setGiphyButton": "Kies een Giphy afbeelding", + "noContent": "(Dit retropunt heeft geen inhoud)", + "by": "door", + "upVote": "omhoog stemmen", + "downVote": "tegenstemmen", + "voteRemainingMultiple": "Je hebt nog {{number}} {{type}}s over.", + "voteRemainingOne": "Je hebt nog maar één {{type}} over, maak het mee!", + "voteRemainingNone": "Je hebt geen {{type}} over.", + "toggleGiphyButton": "Aan- en uitschakelen Giphy afbeelding" + }, + "Customize": { + "title": "Sessie aanpassen", + "votingCategory": "Stemmen", + "votingCategorySub": "Instellen regels voor stemmen", + "postCategory": "Retropunten instellingen", + "postCategorySub": "Instellen regels wat een gebruiker kan doen wanneer hij reageert op een retropunt", + "customTemplateCategory": "Kolommen template", + "customTemplateCategorySub": "Instellen aantal kolommen en hun specificaties", + "startButton": "Start de sessie", + "editButton": "Vernieuwen", + "maxUpVotes": "Maximum up-votes", + "maxUpVotesHelp": "Maximum aantal 'likes' die een gebruiker mag uitbrengen", + "maxDownVotes": "Maximum down-votes", + "maxDownVotesHelp": "Maximum aantal 'dislikes' die een gebruiker mag uitbrengen", + "maxPosts": "Maximum aantal berichten per gebruiker", + "maxPostsHelp": "Maximum aantal berichten dat een gebruiker per sessie kan maken", + "allowSelfVoting": "Zelf-stemmen toestaan", + "allowSelfVotingHelp": "Of een gebruiker op zijn eigen retropunten mag stemmen", + "allowMultipleVotes": "Meerdere stemmen toestaan", + "allowMultipleVotesHelp": "Of een gebruiker meerdere stemmen op hetzelfde retropunt kan uitbrengen", + "allowActions": "Acties toestaan", + "allowActionsHelp": "Toestaan van 'Acties' veld (follow-up) op elk retropunt", + "allowAuthorVisible": "Toon auteur", + "allowAuthorVisibleHelp": "Tonen van auteur op het retropunt.", + "newPostsFirst": "Eerst nieuwe berichten toevoegen", + "newPostsFirstHelp": "Nieuwe berichten worden bovenaan de kolom toegevoegd", + "allowGiphy": "Giphy toestaan", + "allowGiphyHelp": "Gebruikers toestaan een Giphy afbeelding bij een retropunt te plaatsen", + "allowGrouping": "Groeperen toestaan", + "allowGroupingHelp": "Aanmaken van groepen van retropunten toestaan.", + "allowReordering": "Herordenen toestaan", + "allowReorderingHelp": "Toestaan om retropunten mbv drag-en-drop te herordenen", + "blurCards": "Vervaag Kaarten", + "blurCardsHelp": "Inhoud van kaarten wordt vervaagd totdat de moderator de inhoud onthult", + "template": "Sjabloon", + "templateHelp": "Gebruik een vooringestelde set kolommen", + "numberOfColumns": "Aantal kolommen", + "numberOfColumnsHelp": "Stel het aantal kolommen in", + "makeDefaultTemplate": "Stel in als mijn standaard template" + }, + "PostBoard": { + "customQuestion": "Aangepast kolom", + "notWellQuestion": "Wat kan er beter?", + "wellQuestion": "Wat ging goed?", + "ideasQuestion": "Een geweldig idee om te delen?", + "startQuestion": "Beginnen", + "stopQuestion": "Stoppen", + "continueQuestion": "Blijven doen", + "likedQuestion": "Liked (Leuk)", + "lackedQuestion": "Lacked (Ontbrak)", + "learnedQuestion": "Learned (Geleerd)", + "longedForQuestion": "Longed for (Gewild)", + "anchorQuestion": "Anker", + "boatQuestion": "Boot", + "islandQuestion": "Eiland", + "windQuestion": "Wind", + "rockQuestion": "Steen", + "disconnected": "Je huidige sessie is verbroken", + "reconnect": "Opnieuw verbinden", + "notLoggedIn": "Je bent niet ingelogd. Je kan de sessie bekijken als toeschouwer maar moet inloggen om deel te nemen.", + "error_action_unauthorised": "U bent niet bevoegd om deze actie uit te voeren.", + "error_cannot_edit_group": "Bewerken van de groep is mislukt.", + "error_cannot_edit_post": "Bewerken van post mislukt.", + "error_cannot_get_session": "Kan de sessie gegevens niet ophalen. Herlaad de pagina.", + "error_cannot_register_vote": "Uw stem is niet met succes geregistreerd.", + "error_cannot_save_group": "De groep die je hebt aangemaakt kon niet worden opgeslagen.", + "error_cannot_save_post": "De post die je hebt gemaakt kon niet worden opgeslagen.", + "error_cannot_delete_group": "De groep kon niet verwijderd worden", + "error_cannot_delete_post": "Het bericht kon niet verwijderd worden", + "error_cannot_rename_session": "Hernoemen van de sessie is mislukt", + "error_cannot_save_columns": "Kolommen opslaan mislukt", + "error_cannot_save_options": "Opties opslaan mislukt", + "maxPostsReached": "Je hebt het maximum aantal berichten bereikt dat door de moderator is ingesteld.", + "iAmDone": "Ik ben klaar!", + "iAmNotDoneYet": "Ik ben nog niet klaar...", + "userIsReady": "{{user}} is klaar!" + }, + "GameMenu": { + "board": "Bord", + "summary": "Samenvatting" + }, + "Template": { + "default": "Standaard", + "wellNotWell": "Goed / Niet goed", + "startStopContinue": "Start / Stop / Blijven doen", + "fourLs": "De 4 L'en", + "sailboat": "Zeilboot" + }, + "Clients": { + "header": "Deelnemers:", + "joined": "{{users}} kwam binnen.", + "left": "{{users}} is weggegaan." + }, + "Join": { + "welcome": "Welkom bij Retrospected", + "standardTab": { + "header": "Starten", + "text": "Klik hieronder en begin je retrospective:", + "button": "Start een nieuwe sessie", + "customizeButton": "Aanpassen" + }, + "optionsTab": { + "header": "Opties", + "input": "Naam", + "button": "Start een aangepaste sessie" + }, + "previousTab": { + "header": "Vorige sessies", + "rejoinButton": "Opnieuw deelnemen" + } + }, + "AnonymousLogin": { + "namePlaceholder": "Laat weten wie je bent met je naam", + "buttonLabel": "Laten we beginnen", + "header": "Aanmelden", + "anonymousAuthHeader": "Aanmelden zonder account", + "anonymousAuthDescription": "Hiermee maak je aan anonieme account aan. Hiermee kan geen sessies opslaan en terughalen.", + "authenticatingWith": "Authenticeer met", + "or": "of" + }, + "SocialMediaLogin": { + "header": "Social Media authenticatie", + "info": "Dit gebruikt je social media account en slaat de sessies op onder je account. Er is geen wachtwoord nodig." + }, + "AuthCommon": { + "emailField": "E-mailadres", + "passwordField": "Wachtwoord", + "nameField": "Uw naam (voor weergegeven doelen)", + "passwordScoreWords": [ + "zwak", + "zwak", + "niet helemaal", + "goed", + "sterk" + ] + }, + "AccountLogin": { + "header": "Wachtwoord", + "loginButton": "Aanmelden", + "info": "Log in met je e-mailadres en wachtwoord.", + "registerLink": "Niet geregistreerd? Klik hier", + "forgotPasswordLink": "Wachtwoord vergeten?", + "errorEmailPasswordIncorrect": "Uw referenties zijn onjuist." + }, + "Register": { + "header": "Registreren", + "info": "Krijg jezelf een Retrospected account!", + "registerButton": "Registreren", + "errorAlreadyRegistered": "Dit e-mailadres is al geregistreerd", + "errorGeneral": "Er is een fout opgetreden tijdens het aanmaken van uw account.", + "messageSuccess": "Bedankt! U ontvangt binnenkort een e-mail om uw account te valideren.", + "errorInvalidEmail": "Voer een geldig e-mailadres in" + }, + "ValidateAccount": { + "success": "Je e-mail is correct gevalideerd. Ik ga je in een paar seconden aanmelden!", + "error": "Er is een fout opgetreden bij het valideren van je e-mail.", + "loading": "We zijn je e-mailadres aan het valideren. Een ogenblik geduld." + }, + "ResetPassword": { + "doneMessage": "Klaar! Neem een kijkje in uw e-mails, u krijgt een link om uw wachtwoord te resetten.", + "header": "Wachtwoord opnieuw instellen", + "resetButton": "Wachtwoord opnieuw instellen", + "info": "Wachtwoord vergeten? Geen probleem. Voer hieronder uw e-mailadres in en u krijgt een reset e-mail prompt.", + "success": "Je wachtwoord is bijgewerkt. Ik ga je in een paar seconden aanmelden!", + "error": "Er is een fout opgetreden bij het bijwerken van uw wachtwoord.", + "loading": "We zijn je wachtwoord aan het bijwerken. Een ogenblik geduld.", + "resetInfo": "Geef een nieuw wachtwoord op" + }, + "SummaryBoard": { + "noPosts": "Er zijn geen retropunten om te tonen", + "copyAsMarkdown": "Kopieer de samenvatting als Markdown", + "copyAsRichText": "Kopieer de samenvatting als rich-text", + "copySuccessful": "Je hebt de samenvatting succesvol naar het klembord gekopieerd" + }, + "SessionName": { + "defaultSessionName": "Mijn Retrospective" + }, + "Invite": { + "inviteButton": "Uitnodigen", + "dialog": { + "title": "Nodig mensen uit voor jouw retrospective", + "text": "Stuur de mensen die je wil uitnodigen voor jouw retrospective sessie de volgende url", + "copyButton": "Kopieer URL naar klembord" + } + }, + "Generic": { + "ok": "Ok", + "cancel": "Annuleren" + }, + "Actions": { + "tooltip": "Maak een actie op de achterkant van dit item", + "label": "Open het actiepaneel", + "summaryTitle": "Jouw acties", + "title": "Actie" + }, + "DeleteSession": { + "header": "{{name}} '? verwijderen?", + "firstLine": "Het verwijderen van een sessie is onomkeerbaar. Het zal alle berichten, stemmen, groepen en de sessie zelf verwijderen. De gegevens kunnen niet worden hersteld.", + "secondLine": "Weet u zeker dat u deze sessie en alle inhoud wilt verwijderen?", + "yesImSure": "Ja, dat weet ik zeker", + "cancel": "Nee, het spijt me, ik heb een fout gemaakt" + }, + "RevealCards": { + "buttonLabel": "Onthul", + "dialogTitle": "Alle kaarten vrijgeven", + "dialogContent": "Dit zal alle wazige kaarten voor iedereen onthullen. Dit kan niet ongedaan worden gemaakt.", + "confirmButton": "Laat ons onthullen!", + "cancelButton": "Nee, bedankt" + }, + "AccountPage": { + "anonymousError": "Anonieme accounts kunnen geen toegang hebben tot hun profiel (omdat ze geen account hebben).", + "details": { + "header": "Uw gegevens", + "username": "Gebruikersnaam", + "email": "E-mailadres", + "accountType": "Klant type" + }, + "plan": { + "header": "Uw abonnement", + "plan": "Abonnement", + "youAreOwner": "U bent de eigenaar van dit abonnement, via het onderstaande abonnement.", + "youAreMember": "U bent op dit plan via iemands abonnement." + }, + "subscription": { + "header": "Uw abonnement", + "manageButton": "Mijn abonnement beheren", + "membersEditor": { + "title": "Jouw team", + "limitReached": "Je hebt de limiet van je abonnement bereikt ({{limit}} gebruikers, waaronder jezelf). Verwijder de leden, of upgrade naar een onbeperkt bedrijfsaccount.", + "info": "Voeg hieronder e-mails toe om Pro-accounts tot {{limit}} andere collega's toe te kennen. Druk op Enter na elk e-mailadres." + } + }, + "trial": { + "header": "Uw proefperiode", + "yourTrialWillExpireIn": "Je proefperiode loopt af over {{date}}.", + "subscribe": "Nu abonneren" + }, + "deleteAccount": { + "title": "AVG", + "warning": "Je hebt het recht om vergeten te worden. Dat gezegd hebbende, wees voorzichtig bij het verwijderen van je account. Dit kan niet ongedaan worden gemaakt.", + "deleteData": "Verwijder mijn gegevens", + "modal": { + "confirm": { + "title": "Weet je het zeker?", + "description": "Daar kunnen we niet op terugkomen.", + "confirmation": "Ja dat ik al mijn gegevens wil verwijderen", + "cancellation": "Haal me hier uit" + }, + "subheader": "Kies wat u wilt verwijderen", + "deleteAccount": "Verwijder uw account en alle identiteiten die aan uw e-mail zijn gekoppeld.", + "recommended": "Aanbevolen", + "deleteSessions": { + "main": "Moeten we de sessies verwijderen (retrospectives) die u hebt aangemaakt?", + "selected": "Uw sessies en al hun gegevens, inclusief berichten en stemmen van anderen, worden permanent verwijderd.", + "unselected": "Je sessies worden bewaard en de auteur wordt anonieme gebruiker." + }, + "deletePosts": { + "main": "Moeten we alle berichten die je schreef verwijderen?", + "selected": "Je berichten in elke sessie en de bijbehorende stemmen en acties worden permanent verwijderd.", + "unselected": "Je berichten worden bewaard, maar ze worden geassocieerd met een anonieme gebruiker." + }, + "deleteVotes": { + "main": "Moeten we ook al je stemmen verwijderen?", + "selected": "Uw stemmen in alle sessies zullen permanent worden verwijderd.", + "unselected": "Uw stemmen worden bewaard, maar ze worden geassocieerd met een anonieme gebruiker." + }, + "deleteAccountButton": "VERWIJDER UW ACCOUNT", + "cancelButton": "annuleren" + } + } + }, + "SubscribePage": { + "alertAlreadyPro": "U bent al Pro-gebruiker, dus u heeft mogelijk geen behoefte aan een ander abonnement.", + "alertAlreadySubscribed": "Je hebt al een abonnement, dus misschien heb je geen ander abonnement nodig.", + "currency": { + "title": "valuta", + "description": "Kies een valuta waarmee u gefactureerd wilt worden", + "warning": "Uw account is al ingesteld om {{currency}}te gebruiken, dus u kunt de valuta niet meer wijzigen." + }, + "plan": { + "title": "Abonnement", + "description": "Kies het abonnement dat past bij uw keuze!" + }, + "domain": { + "title": "Domein", + "description": "Uw onbeperkte abonnement is van toepassing op een bepaald domein. Elke gebruiker met dit e-maildomein wordt automatisch een Pro-gebruiker.", + "invalidDomain": "Geef een geldig domein. Het domein mag geen gratis of onbruikbaar e-maildomein zijn." + }, + "subscribe": { + "title": "Afrekenen", + "description": "U wordt doorgestuurd naar onze partner Stripe, voor betaling", + "cannotRegisterWithAnon": "Je moet ingelogd zijn met een OAuth of Wachtwoordaccount om door te gaan.", + "checkout": "Afrekenen" + } + }, + "SubscribeModal": { + "title": "Pro abonnement", + "header": "Retrospecte Pro", + "description": "Bescherm de gegevens van uw bedrijf door u te abonneren op Retrospected Pro. Met Retrospected Pro krijgt u de volgende functies en meer:", + "features": { + "encryptedSession": { + "title": "Versleutelde sessies", + "description": "Uw gegevens zijn versleuteld in uw browser, waardoor elke decodering onmogelijk wordt gemaakt op de Retrospected server." + }, + "privateSessions": { + "title": "Privé sessies", + "description": "Zorg ervoor dat alleen erkende mensen toegang hebben tot uw sessie." + }, + "unlimitedPosts": { + "title": "Onbeperkt aantal berichten", + "description": "Met een Pro-abonnement krijg je onbeperkt berichten." + } + }, + "subscribeButton": "Abonneren", + "payButton": "Selecteren", + "cancelButton": "annuleren", + "startTrial": "30-dagen Proef" + }, + "Products": { + "team": "Perfect voor kleinere teams, u kunt maximaal 20 collega's selecteren die zullen worden geüpgraded naar een Pro-account.", + "unlimited": "Als u een groter bedrijf bent, kunt u genieten van een onbeperkt aantal Pro-accounts.", + "self-hosted": "Retrospecteerd op gebouwen, eenmalige vergoeding en onbeperkte updates. Houd de totale controle over uw gegevens voorgoed.", + "users": "{{users}} gebruikers", + "unlimited_seats": "Onbeperkt", + "month": "maand", + "year": "Jaar", + "wantToPayYearly": "Ik wil jaarlijks betalen (elke 12 maanden) en een maand gratis per jaar!" + }, + "Encryption": { + "createEncryptedSession": "Versleutelde sessie", + "sessionNotEncrypted": "Deze sessie is niet versleuteld.", + "sessionEncryptedHaveKeyTooltip": "Deze sessie is versleuteld, en de sleutel wordt opgeslagen in uw browser. U kunt deze sessie openen zonder het wachtwoord opnieuw op te geven.", + "sessionEncryptedNoKeyTooltip": "Deze sessie is versleuteld en de sleutel is niet opgeslagen in uw browser. U wordt gevraagd om de decoderingssleutel bij het openen van deze sessie.", + "sessionEncryptedWrongKeyTooltip": "Deze sessie is versleuteld, en de sleutel die je hebt opgeslagen is niet de juiste sleutel.", + "newEncryptedSessionWarningTitle": "Deze sessie is lokaal versleuteld", + "newEncryptedSessionWarningContent": "Het is erg belangrijk dat je de volledige URL (die de sleutel bevat) ergens veilig opslaat, of ten minste de encryptiesleutel: {{key}}. Als u deze encryptiesleutel verliest, kan er niets worden gedaan om de gegevens op te halen.", + "sessionEncryptionError": "Deze sessie is versleuteld, en het lijkt erop dat de decodering sleutel niet lokaal is opgeslagen. Gebruik de originele link, inclusief de ontsleutel.", + "passwordModalTitle": "Versleutelde sessie - Voer wachtwoord in", + "passwordModelIncorrect": "De encryptiesleutel is onjuist." + }, + "Private": { + "lockSuccessNotification": "Je sessie is succesvol privé gemaakt. Er kunnen geen nieuwe deelnemers deelnemen.", + "unlockSuccessNotification": "Je sessie is openbaar gemaakt. Iedereen kan lid worden.", + "lockButton": "Privé maken", + "unlockButton": "Openbaar maken", + "lockDescription": "U staat op het punt om de sessie privé te maken. Alleen de huidige deelnemers (hieronder vermeld) zullen toegang tot deze sessie krijgen zodra ze zijn vergrendeld.", + "cancelButton": "annuleren", + "sessionLockedTitle": "Deze sessie is privé.", + "sessionLockedDescription": "Vraag de moderator om hem te ontgrendelen zodat je kan inloggen. Vernieuw vervolgens deze pagina.", + "sessionNonProTitle": "Deze sessie is alleen toegankelijk voor Pro-gebruikers", + "sessionNonProDescription": "Deze sessie maakt gebruik van functies die alleen beschikbaar zijn voor Pro-gebruikers. Vraag de moderator of abonnementhouder om u een Pro-account te geven.", + "sessionIsPublic": "Deze sessie is openbaar en voor iedereen toegankelijk.", + "sessionIsPrivate": "Deze sessie is privé, en u hebt toegang.", + "sessionIsPrivateNoAccess": "Deze sessie is privé, maar u hebt geen toegang." + }, + "TrialPrompt": { + "allowanceReachedTitle": "Je hebt je gratis toelage bereikt", + "allowanceReachedDescription": "Om onbeperkte berichten te krijgen, abonneer u alstublieft op Retrospected Pro", + "nearEndAllowanceTitle": "U nadert het einde van uw quotum", + "nearEndAllowanceDescription": "Je hebt nog ongeveer {{quota}} berichten over", + "onTrialTitle": "Retrospected Pro - Proef", + "remainingTrialSentence": "Je hebt {{remaining}} over je proefperiode.", + "trialEndedTitle": "Uw Retrospected Pro-proefperiode is beëindigd", + "trialEndedSentence": "Abonneer vandaag om toegang te krijgen tot de Pro functies.", + "subscribeNow": "Abonneer je nu!" + }, + "Chat": { + "writeAMessage": "Schrijf hier een bericht..." + } +} \ No newline at end of file diff --git a/frontend/src/translations/locales/pl-PL.json b/frontend/src/translations/locales/pl-PL.json new file mode 100644 index 000000000..4ad40c07d --- /dev/null +++ b/frontend/src/translations/locales/pl-PL.json @@ -0,0 +1,423 @@ +{ + "Header": { + "subtitle": "Dobry sposób by ponarzekać zgodnie z duchem Agile", + "logout": "Wyloguj", + "leave": "Wyjdź", + "summaryMode": "Tryb Podsumowania", + "account": "Moje konto", + "adminPanel": "Panel administracyjny" + }, + "LanguagePicker": { + "header": "Wybierz język" + }, + "Main": { + "hint": "Możesz zaprosić inne osoby do tej sesji wysyłając im URL" + }, + "Home": { + "welcome": "Witaj, {{name}}" + }, + "PreviousGame": { + "createdBy": "Utworzony przez", + "posts_one": "postuj", + "posts_other": "posty", + "participants_one": "uczestnik", + "participants_other": "uczestnicy", + "votes_one": "zagłosuj", + "votes_other": "głosy", + "actions_one": "Akcja", + "actions_other": "Akcje" + }, + "Column": { + "createGroupTooltip": "Utwórz grupę do grupowych postów razem" + }, + "Group": { + "emptyGroupTitle": "To jest pusta grupa", + "emptyGroupContent": "Przenieś post tutaj, aby wypełnić tę grupę" + }, + "Post": { + "openExtra": "Dodatkowe funkcje", + "closeExtra": "Zamknij", + "vote": "głos", + "votes": "głosów", + "deleteButton": "Usuń", + "setActionButton": "Ustaw akcję", + "setGiphyButton": "Wybierz obraz Giphy", + "noContent": "(Ten wpis nie ma zawartości)", + "by": "przez", + "upVote": "głos pozytywny", + "downVote": "Głos negatywny", + "voteRemainingMultiple": "Pozostało Ci {{number}} {{type}}s.", + "voteRemainingOne": "Pozostało Ci tylko jeden {{type}} , zliczaj się!", + "voteRemainingNone": "Nie masz jeszcze żadnych {{type}}.", + "toggleGiphyButton": "Przełącz obraz Giphy" + }, + "Customize": { + "title": "Dostosuj swoją sesję", + "votingCategory": "Głosowanie", + "votingCategorySub": "Ustaw reguły dotyczące polubień i polubień", + "postCategory": "Ustawienia postów", + "postCategorySub": "Ustaw reguły co użytkownik może zrobić podczas tworzenia lub przeglądania wpisu", + "customTemplateCategory": "Szablon kolumny", + "customTemplateCategorySub": "Ustaw liczbę kolumn i ich właściwości", + "startButton": "Rozpocznij sesję", + "editButton": "Aktualizuj", + "maxUpVotes": "Maksymalna liczba głosów", + "maxUpVotesHelp": "Maksymalna liczba głosów 'polubienia', które użytkownik może rzucić", + "maxDownVotes": "Maksymalna liczba głosów", + "maxDownVotesHelp": "Maksymalna liczba głosów, które użytkownik może rzucić", + "maxPosts": "Maksymalna liczba postów na użytkownika", + "maxPostsHelp": "Maksymalna liczba postów, które użytkownik może utworzyć na sesję", + "allowSelfVoting": "Zezwalaj na samodzielne głosowanie", + "allowSelfVotingHelp": "Czy zezwolić użytkownikowi na głosowanie na własny post", + "allowMultipleVotes": "Zezwalaj na wiele głosów", + "allowMultipleVotesHelp": "Czy zezwolić użytkownikowi na wielokrotne głosowanie na ten sam post", + "allowActions": "Zezwól na działania", + "allowActionsHelp": "Czy zezwolić na pole \"Akcja\" (kontynuacja) dla każdego postu", + "allowAuthorVisible": "Pokaż autora", + "allowAuthorVisibleHelp": "Wyświetlaj autora wpisu na samym poście.", + "newPostsFirst": "Dodaj najpierw nowe posty", + "newPostsFirstHelp": "Nowe posty są dodawane w górnej części kolumny", + "allowGiphy": "Zezwalaj na Giphy", + "allowGiphyHelp": "Zezwalaj użytkownikom na ustawianie obrazu Giphy przeciwko wpisowi", + "allowGrouping": "Zezwalaj na grupowanie", + "allowGroupingHelp": "Pozwól tworzyć grupy do grupowania postów", + "allowReordering": "Zezwalaj na ponowne zamawianie", + "allowReorderingHelp": "Zezwalaj na zmianę kolejności postów przez przeciąganie i upuszczanie", + "blurCards": "Rozmycie kart", + "blurCardsHelp": "Zawartość kart jest rozmyta aż moderator ujawni zawartość", + "template": "Szablon", + "templateHelp": "Użyj predefiniowanego zestawu kolumn", + "numberOfColumns": "Liczba kolumn", + "numberOfColumnsHelp": "Ustaw liczbę kolumn", + "makeDefaultTemplate": "Ustaw ten domyślny szablon" + }, + "PostBoard": { + "customQuestion": "Kolumna niestandardowa", + "notWellQuestion": "Co można poprawić?", + "wellQuestion": "Co poszło dobrze?", + "ideasQuestion": "Wspaniały pomysł którym chcesz się podzielić?", + "startQuestion": "Rozpocznij", + "stopQuestion": "Zatrzymaj", + "continueQuestion": "Kontynuuj", + "likedQuestion": "Polubione", + "lackedQuestion": "Brak", + "learnedQuestion": "Uczono", + "longedForQuestion": "Trwa dla", + "anchorQuestion": "Kotwica", + "boatQuestion": "Łódka", + "islandQuestion": "Wyspa", + "windQuestion": "Wiatr", + "rockQuestion": "Skała", + "disconnected": "Zostałeś odłączony od bieżącej sesji.", + "reconnect": "Połącz ponownie", + "notLoggedIn": "Nie jesteś zalogowany. Możesz zobaczyć tę sesję jako obserwator, ale musisz się zalogować, aby wziąć udział.", + "error_action_unauthorised": "Nie masz uprawnień do wykonania tej czynności.", + "error_cannot_edit_group": "Edycja grupy nie powiodła się.", + "error_cannot_edit_post": "Edycja wpisu nie powiodła się.", + "error_cannot_get_session": "Nie można pobrać danych sesji. Proszę odświeżyć stronę.", + "error_cannot_register_vote": "Twój głos nie został pomyślnie zarejestrowany.", + "error_cannot_save_group": "Nie można zapisać utworzonej grupy.", + "error_cannot_save_post": "Nie można zapisać wpisu, który utworzyłeś.", + "error_cannot_delete_group": "Grupa nie mogła zostać usunięta", + "error_cannot_delete_post": "Nie można usunąć posta", + "error_cannot_rename_session": "Zmiana nazwy sesji nie powiodła się", + "error_cannot_save_columns": "Zapisywanie kolumn nie powiodło się", + "error_cannot_save_options": "Zapisywanie opcji nie powiodło się", + "maxPostsReached": "Osiągnąłeś maksymalną liczbę postów ustawionych przez moderatora.", + "iAmDone": "Gotowe!", + "iAmNotDoneYet": "Jeszcze nie skończyłem...", + "userIsReady": "{{user}} jest gotowy!" + }, + "GameMenu": { + "board": "Tablica", + "summary": "Summary" + }, + "Template": { + "default": "Domyślny", + "wellNotWell": "Dobra / Niedobrze", + "startStopContinue": "Rozpocznij / Zatrzymaj / Kontynuuj", + "fourLs": "Cztery litery", + "sailboat": "Łódka żaglowca" + }, + "Clients": { + "header": "Są dziś z nami:", + "joined": "{{users}} dołączył.", + "left": "{{users}} wyszedł." + }, + "Join": { + "welcome": "Witaj w Retrospected", + "standardTab": { + "header": "Stwórz", + "text": "Kliknij poniżej i zacznij retrospektywę:", + "button": "Stwórz nową sesję", + "customizeButton": "Dostosuj" + }, + "optionsTab": { + "header": "Zaawansowane", + "input": "Imię", + "button": "Stwórz custom session" + }, + "previousTab": { + "header": "Poprzednie", + "rejoinButton": "Dołącz ponownie" + } + }, + "AnonymousLogin": { + "namePlaceholder": "Kim dokładnie jesteś? Wprowadź tu swoje imię", + "buttonLabel": "Zacznijmy", + "header": "Logowanie", + "anonymousAuthHeader": "Anonimowe logowanie", + "anonymousAuthDescription": "Spowoduje to utworzenie anonimowego konta. Niektóre funkcje nie będą dostępne.", + "authenticatingWith": "Uwierzytelnianie z", + "or": "lub" + }, + "SocialMediaLogin": { + "header": "OAuth", + "info": "Spowoduje to korzystanie z wybranego przez Ciebie zewnętrznego dostawcy uwierzytelniania. Hasło nie jest przechowywane." + }, + "AuthCommon": { + "emailField": "E-mail", + "passwordField": "Hasło", + "nameField": "Twoje imię (do celów wyświetlenia)", + "passwordScoreWords": [ + "słabe", + "słabe", + "nie całkiem", + "dobry", + "silny" + ] + }, + "AccountLogin": { + "header": "Hasło", + "loginButton": "Logowanie", + "info": "Zaloguj się za pomocą adresu e-mail i hasła.", + "registerLink": "Nie jesteś zarejestrowany? Kliknij tutaj", + "forgotPasswordLink": "Zapomniałeś hasła?", + "errorEmailPasswordIncorrect": "Twoje dane logowania są nieprawidłowe." + }, + "Register": { + "header": "Rejestracja", + "info": "Zdobądź konto wstecz!", + "registerButton": "Rejestracja", + "errorAlreadyRegistered": "Ten e-mail jest już zarejestrowany", + "errorGeneral": "Wystąpił błąd podczas próby utworzenia konta.", + "messageSuccess": "Dziękujemy! Wkrótce powinieneś otrzymać e-mail, aby potwierdzić swoje konto.", + "errorInvalidEmail": "Wprowadź poprawny adres e-mail" + }, + "ValidateAccount": { + "success": "Twój e-mail został poprawnie zweryfikowany. Zaloguj się w sekundę!", + "error": "Wystąpił błąd podczas sprawdzania poprawności adresu e-mail.", + "loading": "Sprawdzamy Twój adres e-mail. Proszę czekać." + }, + "ResetPassword": { + "doneMessage": "Gotowe! Spójrz w swoich wiadomościach, powinieneś uzyskać link do zresetowania hasła.", + "header": "Resetowanie hasła", + "resetButton": "Resetuj hasło", + "info": "Nie pamiętasz hasła? To nie problem. Wpisz swój adres e-mail poniżej, a otrzymasz monit o zresetowanie hasła.", + "success": "Twoje hasło zostało zaktualizowane. Zaloguj się w sekundę!", + "error": "Wystąpił błąd podczas aktualizowania hasła.", + "loading": "Aktualizujemy Twoje hasło. Proszę czekać.", + "resetInfo": "Proszę podać nowe hasło" + }, + "SummaryBoard": { + "noPosts": "Nie ma wpisów do wyświetlenia", + "copyAsMarkdown": "Skopiuj podsumowanie jako Markdown", + "copyAsRichText": "Skopiuj podsumowanie jako bogaty tekst", + "copySuccessful": "Pomyślnie skopiowałeś swoje podsumowanie do schowka" + }, + "SessionName": { + "defaultSessionName": "Moja Retrospektywa" + }, + "Invite": { + "inviteButton": "Zaproś", + "dialog": { + "title": "Zaproś ludzi do swojej retrospektywy", + "text": "By zaprosić ludzi do swojej retrospektywy, po prostu wyślij im następujący URL", + "copyButton": "Skopiuj URL do Schowka" + } + }, + "Generic": { + "ok": "OK", + "cancel": "Anuluj" + }, + "Actions": { + "tooltip": "Utwórz akcję z tyłu tego elementu", + "label": "Otwórz panel Akcja", + "summaryTitle": "Twoje działania", + "title": "Akcja" + }, + "DeleteSession": { + "header": "Usuwanie '{{name}}'?", + "firstLine": "Usunięcie sesji jest nieodwracalne. Usunie ona wszystkie posty, głosy, grupy i samą sesję. Dane nie mogą zostać przywrócone.", + "secondLine": "Czy na pewno chcesz usunąć tę sesję i całą jej zawartość?", + "yesImSure": "Tak, jestem pewien", + "cancel": "Nie, przepraszam, popełniłem błąd" + }, + "RevealCards": { + "buttonLabel": "Ujawnij", + "dialogTitle": "Pokaż wszystkie karty", + "dialogContent": "To ujawni wszystkie niewyraźne karty dla wszystkich. Tej operacji nie można cofnąć.", + "confirmButton": "Pokażmy się!", + "cancelButton": "Nie, dziękuję" + }, + "AccountPage": { + "anonymousError": "Anonimowe konta nie mogą mieć dostępu do swojego profilu (ponieważ nie mają nich).", + "details": { + "header": "Twoje dane", + "username": "Nazwa użytkownika", + "email": "E-mail", + "accountType": "Typ konta" + }, + "plan": { + "header": "Twój plan", + "plan": "Plan", + "youAreOwner": "Jesteś właścicielem tego planu poprzez poniższą subskrypcję.", + "youAreMember": "Jesteś na tym planie poprzez subskrypcję kogoś innego." + }, + "subscription": { + "header": "Twoja subskrypcja", + "manageButton": "Zarządzaj moją subskrypcją", + "membersEditor": { + "title": "Twój zespół", + "limitReached": "Osiągnąłeś limit subskrypcji ({{limit}} użytkowników, w tym siebie). Proszę usunąć członków lub zaktualizować konto do nieograniczonej liczby firm.", + "info": "Dodaj e-maile poniżej, aby przyznać konta Pro maksymalnie {{limit}} innym współpracownikom. Naciśnij Enter po każdym adresie e-mail." + } + }, + "trial": { + "header": "Twój okres próbny", + "yourTrialWillExpireIn": "Twój okres próbny zakończy się za {{date}}.", + "subscribe": "Subskrybuj teraz" + }, + "deleteAccount": { + "title": "RODO", + "warning": "Masz prawo do bycia zapomnianym. Powiedziawszy, uważaj przy usuwaniu konta. Tej operacji nie można cofnąć.", + "deleteData": "Usuń moje dane", + "modal": { + "confirm": { + "title": "Czy jesteś całkowicie pewien?", + "description": "Nie ma odwrotu w tej sprawie.", + "confirmation": "Tak, chcę usunąć wszystkie moje dane", + "cancellation": "Zabierz mnie stąd" + }, + "subheader": "Wybierz co usunąć", + "deleteAccount": "Usuń swoje konto i wszelkie tożsamości powiązane z Twoim adresem e-mail.", + "recommended": "Rekomendowane", + "deleteSessions": { + "main": "Czy powinniśmy usunąć utworzone przez Ciebie sesje (retrospektywy)?", + "selected": "Twoje sesje i wszystkie ich dane, w tym posty i głosy innych osób, zostaną trwale usunięte.", + "unselected": "Twoje sesje zostaną zachowane, a ich autor stanie się anonimowym użytkownikiem." + }, + "deletePosts": { + "main": "Czy powinniśmy usunąć wszystkie wpisy, które napisałeś?", + "selected": "Twoje posty w każdej sesji oraz związane z nimi głosy i akcje zostaną trwale usunięte.", + "unselected": "Twoje posty zostaną zachowane, ale zostaną powiązane z anonimowym użytkownikiem." + }, + "deleteVotes": { + "main": "Czy powinniśmy również usunąć wszystkie Twoje głosy?", + "selected": "Twoje głosy, we wszystkich sesjach zostaną trwale usunięte.", + "unselected": "Twoje głosy zostaną zachowane, ale zostaną powiązane z anonimowym użytkownikiem." + }, + "deleteAccountButton": "USUŃ SWOJE RACHUNEK", + "cancelButton": "Anuluj" + } + } + }, + "SubscribePage": { + "alertAlreadyPro": "Jesteś już użytkownikiem Pro, więc nie potrzebujesz innej subskrypcji.", + "alertAlreadySubscribed": "Masz już subskrypcję, więc może nie potrzebujesz innej subskrypcji.", + "currency": { + "title": "Waluta", + "description": "Wybierz walutę, z którą chcesz być rozliczany", + "warning": "Twoje konto jest już ustawione na {{currency}}, więc nie możesz już zmieniać waluty." + }, + "plan": { + "title": "Plan", + "description": "Wybierz plan, który pasuje do Twojego użycia!" + }, + "domain": { + "title": "Domena", + "description": "Twoja nieograniczona subskrypcja dotyczy danej domeny. Każdy użytkownik z tą domeną e-mail automatycznie stanie się użytkownikiem Pro.", + "invalidDomain": "Proszę podać prawidłową domenę. Domena nie może być darmową lub jednorazową domeną e-mail." + }, + "subscribe": { + "title": "Zamówienie", + "description": "Zostaniesz przekierowany do naszego partnera, Stripe, aby zapłacić", + "cannotRegisterWithAnon": "Musisz być zalogowany na koncie OAuth lub Hasło, aby kontynuować.", + "checkout": "Zamówienie" + } + }, + "SubscribeModal": { + "title": "Subskrypcja Pro", + "header": "Odwrócone Pro", + "description": "Chroń dane swojej firmy poprzez subskrybowanie Przeglądanego Przeglądania. Dzięki Retrospected Pro, uzyskaj następujące funkcje i więcej:", + "features": { + "encryptedSession": { + "title": "Zaszyfrowane sesje", + "description": "Twoje dane są zaszyfrowane w przeglądarce, przez co każde odszyfrowanie jest niemożliwe na serwerze Retrospeed." + }, + "privateSessions": { + "title": "Prywatne sesje", + "description": "Upewnij się, że tylko autoryzowani użytkownicy mogą uzyskać dostęp do Twojej sesji." + }, + "unlimitedPosts": { + "title": "Nielimitowane posty", + "description": "Z subskrypcją Pro, uzyskaj nieograniczone posty." + } + }, + "subscribeButton": "Subskrybuj", + "payButton": "Wybierz", + "cancelButton": "Anuluj", + "startTrial": "30-dniowy okres próbny" + }, + "Products": { + "team": "Idealne dla mniejszych drużyn, możesz wybrać do 20 kolegów, którzy zostaną zaktualizowani do konta Pro.", + "unlimited": "Jeśli jesteś większą firmą, cieszysz się nieograniczoną liczbą kont Pro.", + "self-hosted": "Zmienione na lokale, jednorazowe opłaty i nieograniczone aktualizacje. Zachowaj pełną kontrolę nad swoimi danymi.", + "users": "{{users}} użytkowników", + "unlimited_seats": "Nieograniczona", + "month": "miesiąc", + "year": "rok", + "wantToPayYearly": "Chcę płacić corocznie (co 12 miesięcy) i otrzymywać miesiąc za darmo!" + }, + "Encryption": { + "createEncryptedSession": "Zaszyfrowana sesja", + "sessionNotEncrypted": "Ta sesja nie jest zaszyfrowana.", + "sessionEncryptedHaveKeyTooltip": "Ta sesja jest zaszyfrowana, a klucz jest przechowywany w przeglądarce. Możesz otworzyć tę sesję bez konieczności ponownego podania hasła.", + "sessionEncryptedNoKeyTooltip": "Ta sesja jest zaszyfrowana, a klucz nie jest przechowywany w przeglądarce. Zostaniesz poproszony o klucz deszyfrowania podczas otwierania tej sesji.", + "sessionEncryptedWrongKeyTooltip": "Ta sesja jest zaszyfrowana, a zapisany klucz jest nieprawidłowy.", + "newEncryptedSessionWarningTitle": "Ta sesja jest zaszyfrowana lokalnie", + "newEncryptedSessionWarningContent": "Jest bardzo ważne, aby zapisać pełny adres URL (zawierający klucz) w bezpiecznym miejscu, lub przynajmniej klucz szyfrowania: {{key}}. Jeśli stracisz ten klucz szyfrowania, nie ma nic do zrobienia, aby pobrać dane.", + "sessionEncryptionError": "Ta sesja jest zaszyfrowana i wydaje się, że nie masz klucza deszyfrowanego lokalnie. Użyj oryginalnego linku, w tym klucza deszyfrowania.", + "passwordModalTitle": "Sesja zaszyfrowana - Wprowadź hasło", + "passwordModelIncorrect": "Klucz szyfrowania jest nieprawidłowy." + }, + "Private": { + "lockSuccessNotification": "Twoja sesja została pomyślnie upubliczniona. Żaden nowy uczestnik nie może dołączyć.", + "unlockSuccessNotification": "Twoja sesja została upubliczniona. Każdy może dołączyć.", + "lockButton": "Ustaw jako prywatny", + "unlockButton": "Upublicznij", + "lockDescription": "Zamierzasz sprawić, by sesja była prywatna. Tylko obecni uczestnicy (wymienieni poniżej) będą mieli dostęp do tej sesji po zablokowaniu.", + "cancelButton": "Anuluj", + "sessionLockedTitle": "Ta sesja jest prywatna.", + "sessionLockedDescription": "Poproś swojego moderatora, aby odblokował go, abyś mógł dołączyć. Następnie odśwież tę stronę.", + "sessionNonProTitle": "Ta sesja jest dostępna tylko dla użytkowników Pro", + "sessionNonProDescription": "Ta sesja korzysta z funkcji dostępnych tylko dla użytkowników Pro. Poproś moderatora lub posiadacza subskrypcji, aby dał Ci konto Pro.", + "sessionIsPublic": "Ta sesja jest publiczna i dostępna dla każdego.", + "sessionIsPrivate": "Ta sesja jest prywatna i masz dostęp.", + "sessionIsPrivateNoAccess": "Ta sesja jest prywatna, ale nie masz dostępu." + }, + "TrialPrompt": { + "allowanceReachedTitle": "Osiągnąłeś swój darmowy limit", + "allowanceReachedDescription": "Aby uzyskać nieograniczone posty, proszę subskrybuj Retrospected Pro", + "nearEndAllowanceTitle": "Zbliżasz się do końca swojej kwoty", + "nearEndAllowanceDescription": "Pozostało Ci około {{quota}} postów", + "onTrialTitle": "Retrospected Pro - okres próbny", + "remainingTrialSentence": "{{remaining}} opuściłeś okres próbny.", + "trialEndedTitle": "Twój Retrospected Pro Trial zakończył się", + "trialEndedSentence": "Subskrybuj dzisiaj, aby odzyskać dostęp do funkcji Pro.", + "subscribeNow": "Subskrybuj teraz!" + }, + "Chat": { + "writeAMessage": "Napisz wiadomość tutaj..." + } +} \ No newline at end of file diff --git a/frontend/src/translations/locales/pt-BR.json b/frontend/src/translations/locales/pt-BR.json new file mode 100644 index 000000000..02b922bd2 --- /dev/null +++ b/frontend/src/translations/locales/pt-BR.json @@ -0,0 +1,423 @@ +{ + "Header": { + "subtitle": "Uma ótima maneira de reclamar se divertindo", + "logout": "Desconectar", + "leave": "Sair", + "summaryMode": "Modo Sumário", + "account": "Minha conta", + "adminPanel": "Painel de Administração" + }, + "LanguagePicker": { + "header": "Escolha uma língua" + }, + "Main": { + "hint": "Você pode convidar outras pessoas para esta seção compartilhando a URL" + }, + "Home": { + "welcome": "Bem-vindo, {{name}}" + }, + "PreviousGame": { + "createdBy": "Criado Por", + "posts_one": "publicação", + "posts_other": "publicações", + "participants_one": "participante", + "participants_other": "participantes", + "votes_one": "Votar", + "votes_other": "votos", + "actions_one": "Ação", + "actions_other": "Ações" + }, + "Column": { + "createGroupTooltip": "Criar um grupo para agrupar postagens" + }, + "Group": { + "emptyGroupTitle": "Este grupo está vazio", + "emptyGroupContent": "Mova uma publicação para cá para preencher este grupo" + }, + "Post": { + "openExtra": "Recursos adicionais", + "closeExtra": "FECHAR", + "vote": "Votar", + "votes": "votos", + "deleteButton": "Remover", + "setActionButton": "Definir ação", + "setGiphyButton": "Escolha uma imagem de Giphy", + "noContent": "(Esta postagem não tem conteúdo)", + "by": "Por", + "upVote": "voto-up-vote", + "downVote": "voto negativo", + "voteRemainingMultiple": "Você tem {{number}} {{type}}restantes.", + "voteRemainingOne": "Você tem apenas um {{type}} restante, faça com que ele conte!", + "voteRemainingNone": "Você não tem nenhum {{type}} restante.", + "toggleGiphyButton": "Alternar imagem Giphy" + }, + "Customize": { + "title": "Personalize sua sessão", + "votingCategory": "Votação", + "votingCategorySub": "Definir regras sobre curtidas e não curtidas", + "postCategory": "Configurações de postagem", + "postCategorySub": "Defina as regras sobre o que um usuário pode fazer ao criar ou visualizar uma postagem", + "customTemplateCategory": "Modelo de coluna", + "customTemplateCategorySub": "Define o número de colunas e suas características", + "startButton": "Iniciar a sessão", + "editButton": "Atualização", + "maxUpVotes": "Máximo de Votos Atuais", + "maxUpVotesHelp": "Número máximo de votos 'curtidos' que um usuário pode transmitir", + "maxDownVotes": "Máximo de Votos Inativos", + "maxDownVotesHelp": "Número máximo de votos 'descurtidos' que um usuário pode transmitir", + "maxPosts": "Máximo de postagens por usuário", + "maxPostsHelp": "Número máximo de postagens que um usuário pode criar por sessão", + "allowSelfVoting": "Permitir auto-votação", + "allowSelfVotingHelp": "Se permite que um usuário vote em sua própria publicação", + "allowMultipleVotes": "Permitir Vários Votos", + "allowMultipleVotesHelp": "Se permite que um usuário vote várias vezes na mesma publicação", + "allowActions": "Permitir Ações", + "allowActionsHelp": "Se deseja permitir o campo 'Ação' (seguimento) em cada postagem", + "allowAuthorVisible": "Mostrar autor", + "allowAuthorVisibleHelp": "Mostrar o autor da postagem no próprio post.", + "newPostsFirst": "Adicione novas postagens primeiro", + "newPostsFirstHelp": "Novas postagens são adicionadas no topo da coluna", + "allowGiphy": "Permitir Giphy", + "allowGiphyHelp": "Permitir que os usuários definam uma imagem para Giphy contra um post", + "allowGrouping": "Permitir Agrupamento", + "allowGroupingHelp": "Permitir a criação de grupos para agrupar postagens", + "allowReordering": "Permitir reordenação", + "allowReorderingHelp": "Permitir reordenação de postagens arrastando-se-e-soltar", + "blurCards": "Cartões de Desfoque", + "blurCardsHelp": "O conteúdo dos cartões fica desfocado até que o moderador revele o conteúdo", + "template": "Modelo", + "templateHelp": "Usar um conjunto de colunas pré-definidas", + "numberOfColumns": "Número de colunas", + "numberOfColumnsHelp": "Definir o número de colunas", + "makeDefaultTemplate": "Tornar este meu modelo padrão" + }, + "PostBoard": { + "customQuestion": "Coluna personalizada", + "notWellQuestion": "O que poderia ser melhorado?", + "wellQuestion": "O que deu certo?", + "ideasQuestion": "Compartilhar uma ideia brilhante?", + "startQuestion": "Iniciar", + "stopQuestion": "Interromper", + "continueQuestion": "Continuar", + "likedQuestion": "Curtiu", + "lackedQuestion": "Descompactado", + "learnedQuestion": "Aprendido", + "longedForQuestion": "Longo Para", + "anchorQuestion": "Âncora", + "boatQuestion": "Barco", + "islandQuestion": "Ilha", + "windQuestion": "Vento", + "rockQuestion": "Pedras", + "disconnected": "Você foi desconectado da sessão atual.", + "reconnect": "Reconectar", + "notLoggedIn": "Você não está conectado. Você pode ver esta sessão como um espectador, mas precisa fazer o login para participar.", + "error_action_unauthorised": "Você não tem permissão para executar esta ação.", + "error_cannot_edit_group": "Falha ao editar o grupo.", + "error_cannot_edit_post": "Falha ao editar o post.", + "error_cannot_get_session": "Não foi possível obter os dados da sessão. Por favor, recarregue a página.", + "error_cannot_register_vote": "Seu voto não foi registrado com sucesso.", + "error_cannot_save_group": "O grupo que você criou não pode ser salvo.", + "error_cannot_save_post": "A postagem que você criou não pode ser salva.", + "error_cannot_delete_group": "O grupo não pôde ser excluído", + "error_cannot_delete_post": "A publicação não pôde ser excluída", + "error_cannot_rename_session": "Falha ao renomear a sessão", + "error_cannot_save_columns": "Falha ao salvar colunas", + "error_cannot_save_options": "Opções de salvamento falharam", + "maxPostsReached": "Você atingiu o número máximo de postagens definido pelo moderador.", + "iAmDone": "Estou pronto!", + "iAmNotDoneYet": "Eu não terminei ainda...", + "userIsReady": "{{user}} está pronto!" + }, + "GameMenu": { + "board": "Tabuleiro", + "summary": "Summary" + }, + "Template": { + "default": "Padrão", + "wellNotWell": "Bem / Não Bom", + "startStopContinue": "Iniciar / Parar / Continuar", + "fourLs": "Quatro Ls", + "sailboat": "Veleiro" + }, + "Clients": { + "header": "Participando conosco agora:", + "joined": "{{users}} juntou-se.", + "left": "{{users}} restante(s)." + }, + "Join": { + "welcome": "Bem-vindo ao Retrospected", + "standardTab": { + "header": "Crie uma seção", + "text": "Clique abaixo e inicie a restropectiva:", + "button": "Crie uma nova seção", + "customizeButton": "Personalizar" + }, + "optionsTab": { + "header": "Avançado", + "input": "Insira um nome para sua seção", + "button": "Crie uma seção customizada" + }, + "previousTab": { + "header": "Previous sessions", + "rejoinButton": "Rejoin" + } + }, + "AnonymousLogin": { + "namePlaceholder": "Quem é você? Insira seu nome aqui", + "buttonLabel": "Vamos começar", + "header": "Conectar-se", + "anonymousAuthHeader": "Login Anônimo", + "anonymousAuthDescription": "Isso criará uma conta anônima. Alguns recursos não estarão disponíveis.", + "authenticatingWith": "Autenticando com", + "or": "ou" + }, + "SocialMediaLogin": { + "header": "OAuth", + "info": "Isto usará um provedor de terceiros da sua escolha para autenticar você. Nenhuma senha é armazenada." + }, + "AuthCommon": { + "emailField": "e-mail", + "passwordField": "Palavra-passe", + "nameField": "Seu nome (para fins de exibição)", + "passwordScoreWords": [ + "fraco", + "fraco", + "não é muito", + "bom", + "forte" + ] + }, + "AccountLogin": { + "header": "Palavra-passe", + "loginButton": "Conectar-se", + "info": "Faça o login com seu e-mail e senha.", + "registerLink": "Não registrado? Clique aqui", + "forgotPasswordLink": "Esqueceu-se da sua senha?", + "errorEmailPasswordIncorrect": "Suas credenciais estão incorretas." + }, + "Register": { + "header": "Cadastrar", + "info": "Obtenha uma conta Retrospecionada!", + "registerButton": "Cadastrar", + "errorAlreadyRegistered": "Este e-mail já está registrado", + "errorGeneral": "Ocorreu um erro ao tentar criar a sua conta.", + "messageSuccess": "Obrigado! Você deverá receber um e-mail em breve para validar sua conta.", + "errorInvalidEmail": "Por favor, digite um e-mail válido" + }, + "ValidateAccount": { + "success": "Seu e-mail foi validado corretamente. Vou fazer login em um segundo!", + "error": "Houve um erro ao validar o seu e-mail.", + "loading": "Estamos validando o seu e-mail. Por favor, aguarde." + }, + "ResetPassword": { + "doneMessage": "Pronto! Veja seus e-mails, você deve receber um link para redefinir a sua senha.", + "header": "Recuperar senha", + "resetButton": "Redefinir a senha", + "info": "Esqueceu sua senha? Não é um problema. Digite seu e-mail abaixo e você receberá um pedido de redefinição por e-mail.", + "success": "Sua senha foi atualizada. Vou fazer login em um segundo!", + "error": "Houve um erro ao atualizar a sua senha.", + "loading": "Estamos atualizando sua senha. Aguarde.", + "resetInfo": "Forneça uma nova senha" + }, + "SummaryBoard": { + "noPosts": "Não há nenhuma postagem para exibir", + "copyAsMarkdown": "Copiar o resumo como Markdown", + "copyAsRichText": "Copiar o resumo como Rich Text", + "copySuccessful": "Você copiou o seu resumo para a área de transferência" + }, + "SessionName": { + "defaultSessionName": "Meu Retrospectivo" + }, + "Invite": { + "inviteButton": "Convidar", + "dialog": { + "title": "Convide pessoas para seu retrospectivo", + "text": "Para convidar pessoas para sua sessão retrospectiva, basta enviá-las o seguinte URL", + "copyButton": "Copiar URL para área de transferência" + } + }, + "Generic": { + "ok": "Certo", + "cancel": "Cancelar" + }, + "Actions": { + "tooltip": "Crie uma ação no verso deste item", + "label": "Abra o painel de ação", + "summaryTitle": "Suas ações", + "title": "Açao" + }, + "DeleteSession": { + "header": "Apagando '{{name}}'?", + "firstLine": "A exclusão de uma sessão é irreversível. Ela excluirá todas as postagens, votos, grupos e a sessão em si. Os dados não podem ser restaurados.", + "secondLine": "Tem certeza que deseja excluir esta sessão e todo o seu conteúdo?", + "yesImSure": "Sim, tenho certeza", + "cancel": "Não, desculpe, eu cometi um erro" + }, + "RevealCards": { + "buttonLabel": "Mostrar", + "dialogTitle": "Mostrar todos os cards", + "dialogContent": "Isto revelará todas as cartas desfocadas para todos. Isso não poderá ser desfeito.", + "confirmButton": "Vamos revelar!", + "cancelButton": "Não, obrigado." + }, + "AccountPage": { + "anonymousError": "Contas anônimas não podem ter acesso ao seu perfil (porque não têm uma).", + "details": { + "header": "Suas informações", + "username": "Usuário:", + "email": "e-mail", + "accountType": "Tipo de Conta" + }, + "plan": { + "header": "Seu plano", + "plan": "Planejamento", + "youAreOwner": "Você é o proprietário deste plano, através da assinatura abaixo.", + "youAreMember": "Você está nesse plano por meio da assinatura de outra pessoa." + }, + "subscription": { + "header": "Sua assinatura", + "manageButton": "Gerenciar minha assinatura", + "membersEditor": { + "title": "Seu time", + "limitReached": "Você atingiu o limite de sua assinatura ({{limit}} usuários, incluindo você mesmo). Por favor, remova os membros ou faça o upgrade para uma conta ilimitada da empresa.", + "info": "Adicione e-mails abaixo para conceder contas Pro para até {{limit}} outros colegas. Pressione Enter após cada endereço de e-mail." + } + }, + "trial": { + "header": "Seu período de teste", + "yourTrialWillExpireIn": "Seu período de teste terminará em {{date}}.", + "subscribe": "Inscreva-se agora" + }, + "deleteAccount": { + "title": "RGPD", + "warning": "Você tem o direito de ser esquecido. Dito isso, tenha cuidado ao excluir sua conta. Isso não poderá ser desfeito.", + "deleteData": "Excluir meus dados", + "modal": { + "confirm": { + "title": "Você tem certeza absoluta?", + "description": "Não se pode voltar atrás nesta questão.", + "confirmation": "Sim eu quero apagar todos os meus dados", + "cancellation": "Leve-me daqui fora" + }, + "subheader": "Escolha o que excluir", + "deleteAccount": "Apague sua conta e quaisquer identidades ligadas ao seu e-mail.", + "recommended": "Recomendados", + "deleteSessions": { + "main": "Devemos excluir as sessões (retrospectivas) que você criou?", + "selected": "Suas sessões e todos os seus dados, incluindo publicações e votos de outras pessoas, serão excluídos permanentemente.", + "unselected": "Suas sessões serão mantidas e seu autor se tornará um usuário anônimo." + }, + "deletePosts": { + "main": "Devemos excluir todos os posts que você escreveu?", + "selected": "Seus posts, em qualquer sessão, e seus votos e ações associados serão excluídos permanentemente.", + "unselected": "Suas postagens serão mantidas, mas elas se tornarão associadas a um usuário anônimo." + }, + "deleteVotes": { + "main": "Será que devemos também suprimir todos os seus votos?", + "selected": "Seus votos, em todas as sessões serão permanentemente excluídos.", + "unselected": "Seus votos serão mantidos, mas se tornarão associados a um usuário anônimo." + }, + "deleteAccountButton": "EXCLUIR SUA CONTA", + "cancelButton": "cancelar" + } + } + }, + "SubscribePage": { + "alertAlreadyPro": "Você já é um usuário Pro, então você pode não precisar de outra assinatura.", + "alertAlreadySubscribed": "Você já tem uma assinatura, então você pode não precisar de outra assinatura.", + "currency": { + "title": "moeda", + "description": "Escolha uma moeda em que você gostaria de ser cobrada", + "warning": "Sua conta já está configurada para usar {{currency}}, então você não pode mais alterar a moeda." + }, + "plan": { + "title": "Planejamento", + "description": "Escolha o plano que se adapte ao seu caso de uso!" + }, + "domain": { + "title": "Domínio", + "description": "Sua assinatura ilimitada se aplica a um determinado domínio. Qualquer usuário com este domínio de e-mail se tornará automaticamente um usuário Pro.", + "invalidDomain": "Por favor, forneça um domínio válido. O domínio não pode ser um domínio de e-mail gratuito ou descartável." + }, + "subscribe": { + "title": "Confiramar", + "description": "Você será redirecionado para nosso parceiro, Stripe, para pagamento", + "cannotRegisterWithAnon": "Você precisa estar logado com uma conta OAuth ou senha para continuar.", + "checkout": "Confiramar" + } + }, + "SubscribeModal": { + "title": "Assinatura Pro", + "header": "Retrospected Pro", + "description": "Proteja os dados da sua empresa inscrevendo-se no Retrospected Pro. Com Retrospected Pro, obtenha os seguintes recursos e muito mais:", + "features": { + "encryptedSession": { + "title": "Sessões criptografadas", + "description": "Seus dados estão criptografados no seu navegador, tornando qualquer descriptografia impossível no servidor Retrospecionado." + }, + "privateSessions": { + "title": "Sessões Privadas", + "description": "Certifique-se de que apenas pessoas autorizadas podem acessar sua sessão." + }, + "unlimitedPosts": { + "title": "Postagens ilimitadas", + "description": "Com uma assinatura Pro, receba publicações ilimitadas." + } + }, + "subscribeButton": "Inscrever-se", + "payButton": "Selecionar", + "cancelButton": "cancelar", + "startTrial": "30 dias de teste" + }, + "Products": { + "team": "Perfeito para equipes menores, você pode selecionar até 20 colegas que serão atualizados para uma conta Pro.", + "unlimited": "Se você é uma empresa maior, você vai desfrutar de um número ilimitado de contas Pro.", + "self-hosted": "Retrospectiva no local, taxa única e atualizações ilimitadas. Mantenha o controle total de seus dados, para sempre.", + "users": "{{users}} usuários", + "unlimited_seats": "Ilimitado", + "month": "mês", + "year": "Ano", + "wantToPayYearly": "Quero pagar anualmente (a cada 12 meses) e ganhar um mês grátis por ano!" + }, + "Encryption": { + "createEncryptedSession": "Sessão criptografada", + "sessionNotEncrypted": "Esta sessão não está criptografada.", + "sessionEncryptedHaveKeyTooltip": "Esta sessão é criptografada, e a chave é armazenada no seu navegador. Você pode abrir esta sessão sem precisar fornecer a senha novamente.", + "sessionEncryptedNoKeyTooltip": "Esta sessão é criptografada, e a chave não é armazenada no seu navegador. Você será solicitado pela chave de descriptografia ao abrir esta sessão.", + "sessionEncryptedWrongKeyTooltip": "Esta sessão é criptografada, e a chave armazenada não é a chave correta.", + "newEncryptedSessionWarningTitle": "Esta sessão é criptografada localmente", + "newEncryptedSessionWarningContent": "É muito importante para você salvar a URL completa (que contém a chave) em algum lugar seguro, ou pelo menos a chave de criptografia: {{key}}. Se você perder essa chave de criptografia, não há nada que possa ser feito para recuperar os dados.", + "sessionEncryptionError": "Esta sessão está criptografada, e parece que você não tem a chave de descriptografia armazenada localmente. Por favor, use o link original, incluindo a chave de descriptografia.", + "passwordModalTitle": "Sessão criptografada - Digite a senha", + "passwordModelIncorrect": "A chave de criptografia está incorreta." + }, + "Private": { + "lockSuccessNotification": "Sua sessão foi privada com sucesso. Nenhum novo participante pode participar.", + "unlockSuccessNotification": "Sua sessão foi publicada com sucesso. Qualquer pessoa pode entrar.", + "lockButton": "Tornar privado", + "unlockButton": "Tornar público", + "lockDescription": "Você está prestes a tornar a sessão privada. Apenas os participantes atuais (listados abaixo) terão acesso a esta sessão quando bloqueados.", + "cancelButton": "cancelar", + "sessionLockedTitle": "Esta sessão é privada.", + "sessionLockedDescription": "Por favor, peça ao seu moderador para desbloqueá-lo para que você possa entrar. Em seguida, atualize esta página.", + "sessionNonProTitle": "Esta sessão só é acessível a usuários Pro", + "sessionNonProDescription": "Esta sessão usa recursos apenas disponíveis para usuários Pro. Peça ao moderador ou titular da assinatura para lhe dar uma conta Pro.", + "sessionIsPublic": "Esta sessão é pública e acessível a qualquer um.", + "sessionIsPrivate": "Esta sessão é privada e você tem acesso.", + "sessionIsPrivateNoAccess": "Esta sessão é privada, mas você não tem acesso." + }, + "TrialPrompt": { + "allowanceReachedTitle": "Você alcançou o seu subsídio gratuito", + "allowanceReachedDescription": "Para obter publicações ilimitadas, por favor, inscreva-se no Retrospeted Pro", + "nearEndAllowanceTitle": "Você está perto do fim da sua cota", + "nearEndAllowanceDescription": "Você tem cerca de {{quota}} publicações restantes", + "onTrialTitle": "Retrospected Pro - Teste", + "remainingTrialSentence": "Você tem {{remaining}} restantes na sua avaliação.", + "trialEndedTitle": "Seu Teste Retrospected Pro terminou", + "trialEndedSentence": "Assine hoje para recuperar o acesso aos recursos Pro.", + "subscribeNow": "Inscreva-se agora!" + }, + "Chat": { + "writeAMessage": "Escreva uma mensagem aqui..." + } +} \ No newline at end of file diff --git a/frontend/src/translations/locales/pt-PT.json b/frontend/src/translations/locales/pt-PT.json new file mode 100644 index 000000000..f01f4a9cb --- /dev/null +++ b/frontend/src/translations/locales/pt-PT.json @@ -0,0 +1,423 @@ +{ + "Header": { + "subtitle": "Uma boa maneira de se expressar de forma ágil", + "logout": "Desconectar", + "leave": "Sair", + "summaryMode": "Modo de Resumo", + "account": "Minha conta", + "adminPanel": "Painel de Administração" + }, + "LanguagePicker": { + "header": "Escolha um idioma" + }, + "Main": { + "hint": "Você pode convidar outros para esta sessão copiando a URL" + }, + "Home": { + "welcome": "Bem-vindo, {{name}}" + }, + "PreviousGame": { + "createdBy": "Criado Por", + "posts_one": "publicação", + "posts_other": "publicações", + "participants_one": "participante", + "participants_other": "participantes", + "votes_one": "Votar", + "votes_other": "votos", + "actions_one": "Ação", + "actions_other": "Ações" + }, + "Column": { + "createGroupTooltip": "Criar um grupo para agrupar postagens" + }, + "Group": { + "emptyGroupTitle": "Este grupo está vazio", + "emptyGroupContent": "Mova uma publicação para cá para preencher este grupo" + }, + "Post": { + "openExtra": "Recursos adicionais", + "closeExtra": "FECHAR", + "vote": "Votar", + "votes": "votos", + "deleteButton": "excluir", + "setActionButton": "Definir ação", + "setGiphyButton": "Escolha uma imagem de Giphy", + "noContent": "(Esta postagem não tem conteúdo)", + "by": "Por", + "upVote": "voto-up-vote", + "downVote": "voto negativo", + "voteRemainingMultiple": "Você tem {{number}} {{type}}restantes.", + "voteRemainingOne": "Você tem apenas um {{type}} restante, faça com que ele conte!", + "voteRemainingNone": "Você não tem nenhum {{type}} restante.", + "toggleGiphyButton": "Alternar imagem Giphy" + }, + "Customize": { + "title": "Personalize sua sessão", + "votingCategory": "Votação", + "votingCategorySub": "Definir regras sobre curtidas e não curtidas", + "postCategory": "Configurações de postagem", + "postCategorySub": "Defina as regras sobre o que um usuário pode fazer ao criar ou visualizar uma postagem", + "customTemplateCategory": "Modelo de coluna", + "customTemplateCategorySub": "Define o número de colunas e suas características", + "startButton": "Iniciar a sessão", + "editButton": "Atualização", + "maxUpVotes": "Máximo de Votos Atuais", + "maxUpVotesHelp": "Número máximo de votos 'curtidos' que um usuário pode transmitir", + "maxDownVotes": "Máximo de Votos Inativos", + "maxDownVotesHelp": "Número máximo de votos 'descurtidos' que um usuário pode transmitir", + "maxPosts": "Máximo de postagens por usuário", + "maxPostsHelp": "Número máximo de postagens que um usuário pode criar por sessão", + "allowSelfVoting": "Permitir auto-votação", + "allowSelfVotingHelp": "Se permite que um usuário vote em sua própria publicação", + "allowMultipleVotes": "Permitir Vários Votos", + "allowMultipleVotesHelp": "Se permite que um usuário vote várias vezes na mesma publicação", + "allowActions": "Permitir Ações", + "allowActionsHelp": "Se deseja permitir o campo 'Ação' (seguimento) em cada postagem", + "allowAuthorVisible": "Mostrar autor", + "allowAuthorVisibleHelp": "Mostrar o autor da postagem no próprio post.", + "newPostsFirst": "Adicione novas postagens primeiro", + "newPostsFirstHelp": "Novas postagens são adicionadas no topo da coluna", + "allowGiphy": "Permitir Giphy", + "allowGiphyHelp": "Permitir que os usuários definam uma imagem para Giphy contra um post", + "allowGrouping": "Permitir Agrupamento", + "allowGroupingHelp": "Permitir a criação de grupos para agrupar postagens", + "allowReordering": "Permitir reordenação", + "allowReorderingHelp": "Permitir reordenação de postagens arrastando-se-e-soltar", + "blurCards": "Cartões de Desfoque", + "blurCardsHelp": "O conteúdo dos cartões fica desfocado até que o moderador revele o conteúdo", + "template": "Modelo", + "templateHelp": "Usar um conjunto de colunas pré-definidas", + "numberOfColumns": "Número de colunas", + "numberOfColumnsHelp": "Definir o número de colunas", + "makeDefaultTemplate": "Tornar este meu modelo padrão" + }, + "PostBoard": { + "customQuestion": "Coluna personalizada", + "notWellQuestion": "O que poderia ser melhorado?", + "wellQuestion": "O que correu bem?", + "ideasQuestion": "Uma ideia brilhante para compartilhar?", + "startQuestion": "Iniciar", + "stopQuestion": "Interromper", + "continueQuestion": "Continuar", + "likedQuestion": "Curtiu", + "lackedQuestion": "Descompactado", + "learnedQuestion": "Aprendido", + "longedForQuestion": "Longo Para", + "anchorQuestion": "Âncora", + "boatQuestion": "Barco", + "islandQuestion": "Ilha", + "windQuestion": "Vento", + "rockQuestion": "Pedras", + "disconnected": "Você foi desconectado da sessão atual.", + "reconnect": "Reconectar", + "notLoggedIn": "Você não está conectado. Você pode ver esta sessão como um espectador, mas precisa fazer o login para participar.", + "error_action_unauthorised": "Você não tem permissão para executar esta ação.", + "error_cannot_edit_group": "Falha ao editar o grupo.", + "error_cannot_edit_post": "Falha ao editar o post.", + "error_cannot_get_session": "Não foi possível obter os dados da sessão. Por favor, recarregue a página.", + "error_cannot_register_vote": "Seu voto não foi registrado com sucesso.", + "error_cannot_save_group": "O grupo que você criou não pode ser salvo.", + "error_cannot_save_post": "A postagem que você criou não pode ser salva.", + "error_cannot_delete_group": "O grupo não pôde ser excluído", + "error_cannot_delete_post": "A publicação não pôde ser excluída", + "error_cannot_rename_session": "Falha ao renomear a sessão", + "error_cannot_save_columns": "Falha ao salvar colunas", + "error_cannot_save_options": "Opções de salvamento falharam", + "maxPostsReached": "Você atingiu o número máximo de postagens definido pelo moderador.", + "iAmDone": "Estou pronto!", + "iAmNotDoneYet": "Eu não terminei ainda...", + "userIsReady": "{{user}} está pronto!" + }, + "GameMenu": { + "board": "Tabuleiro", + "summary": "Summary" + }, + "Template": { + "default": "Padrão", + "wellNotWell": "Bem / Não Bom", + "startStopContinue": "Iniciar / Parar / Continuar", + "fourLs": "Quatro Ls", + "sailboat": "Veleiro" + }, + "Clients": { + "header": "Participantes:", + "joined": "{{users}} juntou-se.", + "left": "{{users}} restante(s)." + }, + "Join": { + "welcome": "Bem vindo ao Retrospecionado", + "standardTab": { + "header": "Crio", + "text": "Clique abaixo e comece retrospectivo:", + "button": "Criar uma nova sessão", + "customizeButton": "Personalizar" + }, + "optionsTab": { + "header": "Opções", + "input": "Nome:", + "button": "Criar sessão personalizada" + }, + "previousTab": { + "header": "Anterior", + "rejoinButton": "Rejoin" + } + }, + "AnonymousLogin": { + "namePlaceholder": "Por favor, insira um nome ou apelido aqui para continuar", + "buttonLabel": "Conectar-se", + "header": "Conectar-se", + "anonymousAuthHeader": "Login Anônimo", + "anonymousAuthDescription": "Isso criará uma conta anônima. Alguns recursos não estarão disponíveis.", + "authenticatingWith": "Autenticando com", + "or": "ou" + }, + "SocialMediaLogin": { + "header": "OAuth", + "info": "Isto usará um provedor de terceiros da sua escolha para autenticar você. Nenhuma senha é armazenada." + }, + "AuthCommon": { + "emailField": "e-mail", + "passwordField": "Palavra-passe", + "nameField": "Seu nome (para fins de exibição)", + "passwordScoreWords": [ + "fraco", + "fraco", + "não é muito", + "bom", + "forte" + ] + }, + "AccountLogin": { + "header": "Palavra-passe", + "loginButton": "Conectar-se", + "info": "Faça o login com seu e-mail e senha.", + "registerLink": "Não registrado? Clique aqui", + "forgotPasswordLink": "Esqueceu-se da sua senha?", + "errorEmailPasswordIncorrect": "Suas credenciais estão incorretas." + }, + "Register": { + "header": "Cadastrar", + "info": "Obtenha uma conta Retrospecionada!", + "registerButton": "Cadastrar", + "errorAlreadyRegistered": "Este e-mail já está registrado", + "errorGeneral": "Ocorreu um erro ao tentar criar a sua conta.", + "messageSuccess": "Obrigado! Você deverá receber um e-mail em breve para validar sua conta.", + "errorInvalidEmail": "Por favor, digite um e-mail válido" + }, + "ValidateAccount": { + "success": "Seu e-mail foi validado corretamente. Vou fazer login em um segundo!", + "error": "Houve um erro ao validar o seu e-mail.", + "loading": "Estamos validando o seu e-mail. Por favor, aguarde." + }, + "ResetPassword": { + "doneMessage": "Pronto! Veja seus e-mails, você deve receber um link para redefinir a sua senha.", + "header": "Recuperar senha", + "resetButton": "Redefinir a senha", + "info": "Esqueceu sua senha? Não é um problema. Digite seu e-mail abaixo e você receberá um pedido de redefinição por e-mail.", + "success": "Sua senha foi atualizada. Vou fazer login em um segundo!", + "error": "Houve um erro ao atualizar a sua senha.", + "loading": "Estamos atualizando sua senha. Aguarde.", + "resetInfo": "Forneça uma nova senha" + }, + "SummaryBoard": { + "noPosts": "Não há nenhuma postagem para exibir", + "copyAsMarkdown": "Copiar o resumo como Markdown", + "copyAsRichText": "Copiar o resumo como Rich Text", + "copySuccessful": "Você copiou o seu resumo para a área de transferência" + }, + "SessionName": { + "defaultSessionName": "Meu Retrospectivo" + }, + "Invite": { + "inviteButton": "Convidar", + "dialog": { + "title": "Convide pessoas para seu retrospectivo", + "text": "Para convidar pessoas para sua sessão retrospectiva, basta enviá-las o seguinte URL", + "copyButton": "Copiar URL para área de transferência" + } + }, + "Generic": { + "ok": "Certo", + "cancel": "cancelar" + }, + "Actions": { + "tooltip": "Criar uma ação na parte de trás deste item", + "label": "Abrir o painel de ação", + "summaryTitle": "Suas ações", + "title": "Acão" + }, + "DeleteSession": { + "header": "Apagando '{{name}}'?", + "firstLine": "A exclusão de uma sessão é irreversível. Ela excluirá todas as postagens, votos, grupos e a sessão em si. Os dados não podem ser restaurados.", + "secondLine": "Tem certeza que deseja excluir esta sessão e todo o seu conteúdo?", + "yesImSure": "Sim, tenho certeza", + "cancel": "Não, desculpe, eu cometi um erro" + }, + "RevealCards": { + "buttonLabel": "Mostrar", + "dialogTitle": "Mostrar todos os cards", + "dialogContent": "Isto revelará todas as cartas desfocadas para todos. Isso não poderá ser desfeito.", + "confirmButton": "Vamos revelar!", + "cancelButton": "Não, obrigado." + }, + "AccountPage": { + "anonymousError": "Contas anônimas não podem ter acesso ao seu perfil (porque não têm uma).", + "details": { + "header": "Suas informações", + "username": "Usuário:", + "email": "e-mail", + "accountType": "Tipo de Conta" + }, + "plan": { + "header": "Seu plano", + "plan": "Planejamento", + "youAreOwner": "Você é o proprietário deste plano, através da assinatura abaixo.", + "youAreMember": "Você está nesse plano por meio da assinatura de outra pessoa." + }, + "subscription": { + "header": "Sua assinatura", + "manageButton": "Gerenciar minha assinatura", + "membersEditor": { + "title": "Seu time", + "limitReached": "Você atingiu o limite de sua assinatura ({{limit}} usuários, incluindo você mesmo). Por favor, remova os membros ou faça o upgrade para uma conta ilimitada da empresa.", + "info": "Adicione e-mails abaixo para conceder contas Pro para até {{limit}} outros colegas. Pressione Enter após cada endereço de e-mail." + } + }, + "trial": { + "header": "Seu período de teste", + "yourTrialWillExpireIn": "Seu período de teste terminará em {{date}}.", + "subscribe": "Inscreva-se agora" + }, + "deleteAccount": { + "title": "RGPD", + "warning": "Você tem o direito de ser esquecido. Dito isso, tenha cuidado ao excluir sua conta. Isso não poderá ser desfeito.", + "deleteData": "Excluir meus dados", + "modal": { + "confirm": { + "title": "Você tem certeza absoluta?", + "description": "Não se pode voltar atrás nesta questão.", + "confirmation": "Sim eu quero apagar todos os meus dados", + "cancellation": "Leve-me daqui fora" + }, + "subheader": "Escolha o que excluir", + "deleteAccount": "Apague sua conta e quaisquer identidades ligadas ao seu e-mail.", + "recommended": "Recomendados", + "deleteSessions": { + "main": "Devemos excluir as sessões (retrospectivas) que você criou?", + "selected": "Suas sessões e todos os seus dados, incluindo publicações e votos de outras pessoas, serão excluídos permanentemente.", + "unselected": "Suas sessões serão mantidas e seu autor se tornará um usuário anônimo." + }, + "deletePosts": { + "main": "Devemos excluir todos os posts que você escreveu?", + "selected": "Seus posts, em qualquer sessão, e seus votos e ações associados serão excluídos permanentemente.", + "unselected": "Suas postagens serão mantidas, mas elas se tornarão associadas a um usuário anônimo." + }, + "deleteVotes": { + "main": "Será que devemos também suprimir todos os seus votos?", + "selected": "Seus votos, em todas as sessões serão permanentemente excluídos.", + "unselected": "Seus votos serão mantidos, mas se tornarão associados a um usuário anônimo." + }, + "deleteAccountButton": "EXCLUIR SUA CONTA", + "cancelButton": "cancelar" + } + } + }, + "SubscribePage": { + "alertAlreadyPro": "Você já é um usuário Pro, então você pode não precisar de outra assinatura.", + "alertAlreadySubscribed": "Você já tem uma assinatura, então você pode não precisar de outra assinatura.", + "currency": { + "title": "moeda", + "description": "Escolha uma moeda em que você gostaria de ser cobrada", + "warning": "Sua conta já está configurada para usar {{currency}}, então você não pode mais alterar a moeda." + }, + "plan": { + "title": "Planejamento", + "description": "Escolha o plano que se adapte ao seu caso de uso!" + }, + "domain": { + "title": "Domínio", + "description": "Sua assinatura ilimitada se aplica a um determinado domínio. Qualquer usuário com este domínio de e-mail se tornará automaticamente um usuário Pro.", + "invalidDomain": "Por favor, forneça um domínio válido. O domínio não pode ser um domínio de e-mail gratuito ou descartável." + }, + "subscribe": { + "title": "Confiramar", + "description": "Você será redirecionado para nosso parceiro, Stripe, para pagamento", + "cannotRegisterWithAnon": "Você precisa estar logado com uma conta OAuth ou senha para continuar.", + "checkout": "Confiramar" + } + }, + "SubscribeModal": { + "title": "Assinatura Pro", + "header": "Retrospected Pro", + "description": "Proteja os dados da sua empresa inscrevendo-se no Retrospected Pro. Com Retrospected Pro, obtenha os seguintes recursos e muito mais:", + "features": { + "encryptedSession": { + "title": "Sessões criptografadas", + "description": "Seus dados estão criptografados no seu navegador, tornando qualquer descriptografia impossível no servidor Retrospecionado." + }, + "privateSessions": { + "title": "Sessões Privadas", + "description": "Certifique-se de que apenas pessoas autorizadas podem acessar sua sessão." + }, + "unlimitedPosts": { + "title": "Postagens ilimitadas", + "description": "Com uma assinatura Pro, receba publicações ilimitadas." + } + }, + "subscribeButton": "Inscrever-se", + "payButton": "Selecionar", + "cancelButton": "cancelar", + "startTrial": "30 dias de teste" + }, + "Products": { + "team": "Perfeito para equipes menores, você pode selecionar até 20 colegas que serão atualizados para uma conta Pro.", + "unlimited": "Se você é uma empresa maior, você vai desfrutar de um número ilimitado de contas Pro.", + "self-hosted": "Retrospectiva no local, taxa única e atualizações ilimitadas. Mantenha o controle total de seus dados, para sempre.", + "users": "{{users}} usuários", + "unlimited_seats": "Ilimitado", + "month": "mês", + "year": "Ano", + "wantToPayYearly": "Quero pagar anualmente (a cada 12 meses) e ganhar um mês grátis por ano!" + }, + "Encryption": { + "createEncryptedSession": "Sessão criptografada", + "sessionNotEncrypted": "Esta sessão não está criptografada.", + "sessionEncryptedHaveKeyTooltip": "Esta sessão é criptografada, e a chave é armazenada no seu navegador. Você pode abrir esta sessão sem precisar fornecer a senha novamente.", + "sessionEncryptedNoKeyTooltip": "Esta sessão é criptografada, e a chave não é armazenada no seu navegador. Você será solicitado pela chave de descriptografia ao abrir esta sessão.", + "sessionEncryptedWrongKeyTooltip": "Esta sessão é criptografada, e a chave armazenada não é a chave correta.", + "newEncryptedSessionWarningTitle": "Esta sessão é criptografada localmente", + "newEncryptedSessionWarningContent": "É muito importante para você salvar a URL completa (que contém a chave) em algum lugar seguro, ou pelo menos a chave de criptografia: {{key}}. Se você perder essa chave de criptografia, não há nada que possa ser feito para recuperar os dados.", + "sessionEncryptionError": "Esta sessão está criptografada, e parece que você não tem a chave de descriptografia armazenada localmente. Por favor, use o link original, incluindo a chave de descriptografia.", + "passwordModalTitle": "Sessão criptografada - Digite a senha", + "passwordModelIncorrect": "A chave de criptografia está incorreta." + }, + "Private": { + "lockSuccessNotification": "Sua sessão foi privada com sucesso. Nenhum novo participante pode participar.", + "unlockSuccessNotification": "Sua sessão foi publicada com sucesso. Qualquer pessoa pode entrar.", + "lockButton": "Tornar privado", + "unlockButton": "Tornar público", + "lockDescription": "Você está prestes a tornar a sessão privada. Apenas os participantes atuais (listados abaixo) terão acesso a esta sessão quando bloqueados.", + "cancelButton": "cancelar", + "sessionLockedTitle": "Esta sessão é privada.", + "sessionLockedDescription": "Por favor, peça ao seu moderador para desbloqueá-lo para que você possa entrar. Em seguida, atualize esta página.", + "sessionNonProTitle": "Esta sessão só é acessível a usuários Pro", + "sessionNonProDescription": "Esta sessão usa recursos apenas disponíveis para usuários Pro. Peça ao moderador ou titular da assinatura para lhe dar uma conta Pro.", + "sessionIsPublic": "Esta sessão é pública e acessível a qualquer um.", + "sessionIsPrivate": "Esta sessão é privada e você tem acesso.", + "sessionIsPrivateNoAccess": "Esta sessão é privada, mas você não tem acesso." + }, + "TrialPrompt": { + "allowanceReachedTitle": "Você alcançou o seu subsídio gratuito", + "allowanceReachedDescription": "Para obter publicações ilimitadas, por favor, inscreva-se no Retrospeted Pro", + "nearEndAllowanceTitle": "Você está perto do fim da sua cota", + "nearEndAllowanceDescription": "Você tem cerca de {{quota}} publicações restantes", + "onTrialTitle": "Retrospected Pro - Teste", + "remainingTrialSentence": "Você tem {{remaining}} restantes na sua avaliação.", + "trialEndedTitle": "Seu Teste Retrospected Pro terminou", + "trialEndedSentence": "Assine hoje para recuperar o acesso aos recursos Pro.", + "subscribeNow": "Inscreva-se agora!" + }, + "Chat": { + "writeAMessage": "Escreva uma mensagem aqui..." + } +} \ No newline at end of file diff --git a/frontend/src/translations/locales/ru-RU.json b/frontend/src/translations/locales/ru-RU.json new file mode 100644 index 000000000..2a1bf66e2 --- /dev/null +++ b/frontend/src/translations/locales/ru-RU.json @@ -0,0 +1,403 @@ +{ + "Header": { + "subtitle": "Отличный способ выговориться прилично", + "leave": "Выйти", + "logout": "Выйти с учётной записи", + "summaryMode": "Показать итоги", + "account": null, + "adminPanel": null + }, + "LanguagePicker": { + "header": "Выбрать язык" + }, + "Main": { + "hint": "Просто отправьте ссылку, чтобы пригласить на эту рестроспективу" + }, + "Home": { + "welcome": null + }, + "PreviousGame": { + "createdBy": null, + "posts": null, + "participants": null, + "votes": null, + "actions": null + }, + "Column": { + "createGroupTooltip": null + }, + "Group": { + "emptyGroupTitle": "", + "emptyGroupContent": "" + }, + "Post": { + "openExtra": null, + "closeExtra": null, + "vote": "голос", + "votes": "голоса", + "deleteButton": "Удалить", + "setActionButton": null, + "setGiphyButton": null, + "noContent": "(пусто)", + "by": null, + "upVote": null, + "downVote": null, + "voteRemainingMultiple": null, + "voteRemainingOne": null, + "voteRemainingNone": null, + "toggleGiphyButton": null + }, + "Customize": { + "title": null, + "votingCategory": null, + "votingCategorySub": null, + "postCategory": null, + "postCategorySub": null, + "customTemplateCategory": null, + "customTemplateCategorySub": null, + "startButton": null, + "editButton": null, + "maxUpVotes": null, + "maxUpVotesHelp": null, + "maxDownVotes": null, + "maxDownVotesHelp": null, + "maxPosts": null, + "maxPostsHelp": null, + "allowSelfVoting": null, + "allowSelfVotingHelp": null, + "allowMultipleVotes": null, + "allowMultipleVotesHelp": null, + "allowActions": null, + "allowActionsHelp": null, + "allowAuthorVisible": null, + "allowAuthorVisibleHelp": null, + "newPostsFirst": null, + "newPostsFirstHelp": null, + "allowGiphy": null, + "allowGiphyHelp": null, + "allowGrouping": null, + "allowGroupingHelp": null, + "allowReordering": null, + "allowReorderingHelp": null, + "blurCards": null, + "blurCardsHelp": null, + "template": null, + "templateHelp": null, + "numberOfColumns": null, + "numberOfColumnsHelp": null, + "makeDefaultTemplate": null + }, + "PostBoard": { + "customQuestion": null, + "notWellQuestion": "Что можно улучшить?", + "wellQuestion": "Что было хорошего?", + "ideasQuestion": "Другие хорошие идеи?", + "startQuestion": null, + "editButton": null, + "stopQuestion": null, + "continueQuestion": null, + "likedQuestion": null, + "lackedQuestion": null, + "learnedQuestion": null, + "longedForQuestion": null, + "anchorQuestion": null, + "boatQuestion": null, + "islandQuestion": null, + "windQuestion": null, + "rockQuestion": null, + "disconnected": null, + "reconnect": null, + "notLoggedIn": null, + "error": null, + "maxPostsReached": null, + "iAmDone": null, + "iAmNotDoneYet": null, + "userIsReady": null + }, + "GameMenu": { + "board": "Записи", + "summary": "Cводка" + }, + "Template": { + "default": null, + "wellNotWell": null, + "startStopContinue": null, + "fourLs": null, + "sailboat": null + }, + "Clients": { + "header": "Участники:", + "joined": null, + "left": null + }, + "Join": { + "welcome": "Добро пожаловать в Retrospected", + "standardTab": { + "header": "Новая ретроспектива", + "text": "Нажмите, чтобы начать:", + "button": "Создать новую ретроспективу", + "customizeButton": "Настроить" + }, + "optionsTab": { + "header": "Дополнительно", + "input": "Введите название ретроспективы", + "button": "Создать ретроспективу" + }, + "previousTab": { + "header": "История", + "rejoinButton": "Войти" + } + }, + "AnonymousLogin": { + "namePlaceholder": "Как вас зовут? Введите имя", + "buttonLabel": "Начать", + "header": "Логин", + "anonymousAuthHeader": null, + "anonymousAuthDescription": null, + "authenticatingWith": null, + "or": null + }, + "SocialMediaLogin": { + "header": null, + "info": null + }, + "AuthCommon": { + "emailField": null, + "passwordField": null, + "nameField": null, + "passwordScoreWords": null + }, + "AccountLogin": { + "header": null, + "loginButton": null, + "info": null, + "registerLink": null, + "forgotPasswordLink": null, + "errorEmailPasswordIncorrect": null + }, + "Register": { + "header": null, + "info": null, + "registerButton": null, + "errorAlreadyRegistered": null, + "errorGeneral": null, + "messageSuccess": null, + "errorInvalidEmail": null + }, + "ValidateAccount": { + "success": null, + "error": null, + "loading": null + }, + "ResetPassword": { + "doneMessage": null, + "header": null, + "resetButton": null, + "info": null, + "success": null, + "error": null, + "loading": null, + "resetInfo": null + }, + "SummaryBoard": { + "noPosts": "Здесь пока пусто", + "copyAsMarkdown": "Скопировать как Markdown", + "copyAsRichText": "Скопировать как RTF", + "copySuccessful": "Копирование завершено" + }, + "SessionName": { + "defaultSessionName": "Наша ретроспектива" + }, + "Invite": { + "inviteButton": "Пригласить", + "dialog": { + "title": "Пригласить на ретроспективу", + "text": "Чтобы пригласить на ретроспективу, просто отправьте ссылку", + "copyButton": "Скопировать ссылку" + } + }, + "Generic": { + "ok": "OK", + "cancel": "отменить" + }, + "Actions": { + "tooltip": "Создать действие на задней части этого элемента", + "label": "Откройте панель действий", + "summaryTitle": "Ваши действия", + "title": "действие" + }, + "DeleteSession": { + "header": null, + "firstLine": null, + "secondLine": null, + "yesImSure": null, + "cancel": null + }, + "RevealCards": { + "buttonLabel": null, + "dialogTitle": null, + "dialogContent": null, + "confirmButton": null, + "cancelButton": null + }, + "AccountPage": { + "anonymousError": null, + "details": { + "header": null, + "username": null, + "email": null, + "accountType": null + }, + "plan": { + "header": null, + "plan": null, + "youAreOwner": null, + "youAreMember": null + }, + "subscription": { + "header": null, + "manageButton": null, + "membersEditor": { + "title": null, + "limitReached": null, + "info": null + } + }, + "trial": { + "header": null, + "yourTrialWillExpireIn": null, + "subscribe": null + }, + "deleteAccount": { + "title": null, + "warning": null, + "deleteData": null, + "modal": { + "confirm": { + "title": null, + "description": null, + "confirmation": null, + "cancellation": null + }, + "subheader": null, + "deleteAccount": null, + "recommended": null, + "deleteSessions": { + "main": null, + "selected": null, + "unselected": null + }, + "deletePosts": { + "main": null, + "selected": null, + "unselected": null + }, + "deleteVotes": { + "main": null, + "selected": null, + "unselected": null + }, + "deleteAccountButton": null, + "cancelButton": null + } + } + }, + "SubscribePage": { + "alertAlreadyPro": null, + "alertAlreadySubscribed": null, + "currency": { + "title": null, + "description": null, + "warning": null + }, + "plan": { + "title": null, + "description": null + }, + "domain": { + "title": null, + "description": null, + "invalidDomain": null + }, + "subscribe": { + "title": null, + "description": null, + "cannotRegisterWithAnon": null, + "checkout": null + } + }, + "SubscribeModal": { + "title": null, + "header": null, + "description": null, + "features": { + "encryptedSession": { + "title": null, + "description": null + }, + "privateSessions": { + "title": null, + "description": null + }, + "unlimitedPosts": { + "title": null, + "description": null + } + }, + "subscribeButton": null, + "payButton": null, + "cancelButton": null, + "startTrial": null + }, + "Products": { + "team": null, + "unlimited": null, + "self-hosted": null, + "users": null, + "unlimited_seats": null, + "month": null, + "year": null, + "wantToPayYearly": null + }, + "Encryption": { + "createEncryptedSession": null, + "sessionNotEncrypted": null, + "sessionEncryptedHaveKeyTooltip": null, + "sessionEncryptedNoKeyTooltip": null, + "sessionEncryptedWrongKeyTooltip": null, + "newEncryptedSessionWarningTitle": null, + "newEncryptedSessionWarningContent": null, + "sessionEncryptionError": null, + "passwordModalTitle": null, + "passwordModelIncorrect": null + }, + "Private": { + "lockSuccessNotification": null, + "unlockSuccessNotification": null, + "lockButton": null, + "unlockButton": null, + "lockDescription": null, + "cancelButton": null, + "sessionLockedTitle": null, + "sessionLockedDescription": null, + "sessionNonProTitle": null, + "sessionNonProDescription": null, + "sessionIsPublic": null, + "sessionIsPrivate": null, + "sessionIsPrivateNoAccess": null + }, + "TrialPrompt": { + "allowanceReachedTitle": null, + "allowanceReachedDescription": null, + "nearEndAllowanceTitle": null, + "nearEndAllowanceDescription": null, + "onTrialTitle": null, + "remainingTrialSentence": null, + "trialEndedTitle": null, + "trialEndedSentence": null, + "subscribeNow": null + }, + "Chat": { + "writeAMessage": null + } +} \ No newline at end of file diff --git a/frontend/src/translations/locales/uk-UA.json b/frontend/src/translations/locales/uk-UA.json new file mode 100644 index 000000000..81f47c26f --- /dev/null +++ b/frontend/src/translations/locales/uk-UA.json @@ -0,0 +1,423 @@ +{ + "Header": { + "subtitle": "Хороший спосіб вираження себе на гнучкому шляху", + "logout": "Вихід із системи", + "leave": "Залишити", + "summaryMode": "Анонімний режим", + "account": "Особистий кабінет", + "adminPanel": "Панель адміністрування" + }, + "LanguagePicker": { + "header": "Виберіть мову" + }, + "Main": { + "hint": "Ви можете запросити інших до цього сеансу, скопіювавши URL" + }, + "Home": { + "welcome": "Ласкаво просимо, {{name}}" + }, + "PreviousGame": { + "createdBy": "Створено", + "posts_one": "запис", + "posts_other": "постів", + "participants_one": "учасник", + "participants_other": "учасники", + "votes_one": "голосувати", + "votes_other": "голоси", + "actions_one": "дія", + "actions_other": "дії" + }, + "Column": { + "createGroupTooltip": "Створити групу для групових дописів" + }, + "Group": { + "emptyGroupTitle": "Це порожня група", + "emptyGroupContent": "Перемістити допис сюди, щоб заповнити цю групу" + }, + "Post": { + "openExtra": "Додаткові функції", + "closeExtra": "Закрити", + "vote": "голосувати", + "votes": "голоси", + "deleteButton": "Видалити", + "setActionButton": "Встановити дію", + "setGiphyButton": "Виберіть зображення Giphy", + "noContent": "(Це повідомлення не має змісту)", + "by": "за", + "upVote": "проти голосу", + "downVote": "голос понизливий", + "voteRemainingMultiple": "Залишилось {{number}} {{type}}сек.", + "voteRemainingOne": "У вас залишилось тільки один {{type}} і ви можете зробити цей рахунок!", + "voteRemainingNone": "У вас не залишилося {{type}}.", + "toggleGiphyButton": "Перемкнути зображення Giphy" + }, + "Customize": { + "title": "Налаштуйте вашу сесію", + "votingCategory": "Голосування", + "votingCategorySub": "Встановіть правила про подібні та вподобання", + "postCategory": "Налаштування повідомлень", + "postCategorySub": "Встановіть правила щодо того, що може робити користувач при створенні чи перегляді допису", + "customTemplateCategory": "Шаблон стовпця", + "customTemplateCategorySub": "Встановіть кількість стовпців і їх символів", + "startButton": "Почати сесію", + "editButton": "Оновити", + "maxUpVotes": "Максимальна кількість голосів", + "maxUpVotesHelp": "Максимальна кількість голосів, які надає користувачу можливість", + "maxDownVotes": "Макс Вниз-голосів", + "maxDownVotesHelp": "Максимальна кількість голосів, які користувач може давати голос", + "maxPosts": "Максимум повідомлень для користувача", + "maxPostsHelp": "Максимальна кількість записів, які користувач може створювати на сесію", + "allowSelfVoting": "Дозволити самооцінювання", + "allowSelfVotingHelp": "Дозволити користувачу голосувати за власне повідомлення", + "allowMultipleVotes": "Дозволити кілька голосів", + "allowMultipleVotesHelp": "Чи дозволити користувачу голосувати кілька разів на тому ж повідомленні", + "allowActions": "Дозволити дії", + "allowActionsHelp": "Чи дозволяти поле \"Дія\" (follow-up) в кожному повідомленні", + "allowAuthorVisible": "Показати автора", + "allowAuthorVisibleHelp": "Відображати автора допису на самому повідомленні.", + "newPostsFirst": "Спершу додайте нові повідомлення", + "newPostsFirstHelp": "Нові пости додаються у верхній частині колонки", + "allowGiphy": "Дозволити Giphy", + "allowGiphyHelp": "Дозволити користувачам встановлювати зображення Giphy з постом", + "allowGrouping": "Дозволити групування", + "allowGroupingHelp": "Дозволити створення груп для групових повідомлень", + "allowReordering": "Дозволити повторне замовлення", + "allowReorderingHelp": "Дозволити перегрупування матеріалів перетягуванням", + "blurCards": "Розмиті картки", + "blurCardsHelp": "Зміст карт буде розмитим, поки модератор не отримає вміст", + "template": "Шаблон", + "templateHelp": "Використовувати попередньо визначений набір стовпців", + "numberOfColumns": "Кількість колонок", + "numberOfColumnsHelp": "Встановити кількість стовпців", + "makeDefaultTemplate": "Зробити це моїм типовим шаблоном" + }, + "PostBoard": { + "customQuestion": "Власний стовпець", + "notWellQuestion": "Що можна покращити?", + "wellQuestion": "Що пішло на добре?", + "ideasQuestion": "Блискуча ідея поділитися?", + "startQuestion": "Старт", + "stopQuestion": "Зупинити", + "continueQuestion": "Продовжити", + "likedQuestion": "Вподобано", + "lackedQuestion": "Бракує", + "learnedQuestion": "Вивчено", + "longedForQuestion": "Довгий час для", + "anchorQuestion": "Якір", + "boatQuestion": "Човен", + "islandQuestion": "Острів", + "windQuestion": "Вітер", + "rockQuestion": "Скеля", + "disconnected": "Вас відключено від поточної сесії.", + "reconnect": "Перепід'єднатись", + "notLoggedIn": "Ви не ввійшли. Ви можете переглядати цю сесію в якості глядача, але повинні увійти, щоб брати участь.", + "error_action_unauthorised": "Ви не можете виконати цю дію.", + "error_cannot_edit_group": "Не вдалося змінити групу.", + "error_cannot_edit_post": "Не вдалося внести зміни до повідомлення.", + "error_cannot_get_session": "Не вдалося отримати дані сесії. Будь ласка, оновіть сторінку.", + "error_cannot_register_vote": "Ваш голос не було успішно зареєстровано.", + "error_cannot_save_group": "Не вдалося зберегти групу, створену вами.", + "error_cannot_save_post": "Не вдалося зберегти повідомлення, створене Вами записом.", + "error_cannot_delete_group": "Не вдалося видалити групу", + "error_cannot_delete_post": "Публікація не може бути видалена", + "error_cannot_rename_session": "Перейменування сесії не вдалося", + "error_cannot_save_columns": "Помилка збереження стовпців", + "error_cannot_save_options": "Зберегти параметри не вдалося", + "maxPostsReached": "Ви досягли максимальної кількості повідомлень, встановлених модератором.", + "iAmDone": "Я завершив!", + "iAmNotDoneYet": "Я ще не завершив...", + "userIsReady": "{{user}} готовий!" + }, + "GameMenu": { + "board": "Дошка", + "summary": "Summary" + }, + "Template": { + "default": "Типово", + "wellNotWell": "Коалі/не дуже добре", + "startStopContinue": "Почати / Зупинити / продовжити", + "fourLs": "Чотири Ли", + "sailboat": "Сильний човен" + }, + "Clients": { + "header": "Учасники:", + "joined": "{{users}} приєднався.", + "left": "{{users}} вийшов." + }, + "Join": { + "welcome": "Ласкаво просимо до Retrospeced", + "standardTab": { + "header": "Створити", + "text": "Натисніть нижче та почніть ретроспекцію:", + "button": "Створити нову сесію", + "customizeButton": "Користувацький" + }, + "optionsTab": { + "header": "Опції", + "input": "Ім'я", + "button": "Створити власну сесію" + }, + "previousTab": { + "header": "Попереднє", + "rejoinButton": "Rejoin" + } + }, + "AnonymousLogin": { + "namePlaceholder": "Будь ласка, введіть ім'я або псевдонім тут для продовження", + "buttonLabel": "Логін", + "header": "Логін", + "anonymousAuthHeader": "Анонімний вхід", + "anonymousAuthDescription": "Це створить анонімний обліковий запис. Деякі функції не будуть доступні.", + "authenticatingWith": "Автентифікація з", + "or": "або" + }, + "SocialMediaLogin": { + "header": "OAuth", + "info": "Буде використано сторонніх провайдерів Ваших вибору для аутентифікації вас. Немає паролів." + }, + "AuthCommon": { + "emailField": "Ел. пошта", + "passwordField": "Пароль", + "nameField": "Ваше ім'я (для цілей відображення)", + "passwordScoreWords": [ + "слабкий", + "слабкий", + "не зовсім", + "добре", + "сильний" + ] + }, + "AccountLogin": { + "header": "Пароль", + "loginButton": "Логін", + "info": "Увійдіть за допомогою вашої електронної пошти та пароля.", + "registerLink": "Не зареєстрований? Натисніть тут", + "forgotPasswordLink": "Забули свій пароль?", + "errorEmailPasswordIncorrect": "Облікові дані неправильні." + }, + "Register": { + "header": "Зареєструватися", + "info": "Отримати собі ретроспективний рахунок!", + "registerButton": "Зареєструватися", + "errorAlreadyRegistered": "Такий email вже зареєстрований", + "errorGeneral": "Сталася помилка при спробі створення вашого облікового запису.", + "messageSuccess": "Дякуємо! Незабаром ви отримаєте електронного листа для підтвердження вашого облікового запису.", + "errorInvalidEmail": "Будь ласка, введіть дійсну адресу електронної пошти" + }, + "ValidateAccount": { + "success": "Вашу адресу електронної пошти підтверджено. Я завітаю Вас через секунду!", + "error": "Помилка при перевірці вашої електронної пошти.", + "loading": "Ми перевіряємо вашу електронну пошту. Будь ласка, зачекайте." + }, + "ResetPassword": { + "doneMessage": "Виконано! Погляньте на свої листи, ви отримаєте посилання для зміни пароля.", + "header": "Скидання пароля", + "resetButton": "Скидання пароля", + "info": "Забули ваш пароль? Не проблема. Введіть адресу електронної пошти нижче і ви отримаєте запит на скидання електронної пошти.", + "success": "Ваш пароль було оновлено. Я збираюсь вас увійти за секунду!", + "error": "Помилка при оновленні пароля.", + "loading": "Ми оновлюємо пароль. Будь ласка, зачекайте.", + "resetInfo": "Будь ласка, вкажіть новий пароль" + }, + "SummaryBoard": { + "noPosts": "Немає повідомлень для відображення", + "copyAsMarkdown": "Скопіювати підсумок у вигляді Markdown", + "copyAsRichText": "Копіювати підсумок як Rich Text", + "copySuccessful": "Ви успішно скопіювали своє резюме в буфер обміну" + }, + "SessionName": { + "defaultSessionName": "Моя ретроспектива" + }, + "Invite": { + "inviteButton": "Запросити", + "dialog": { + "title": "Запросити людей до вашої ретроспективи", + "text": "Щоб запросити людей до вашої ретроспективної сесії, просто відправте їм наступний URL", + "copyButton": "Скопіювати URL в буфер обміну" + } + }, + "Generic": { + "ok": "Гаразд", + "cancel": "Скасувати" + }, + "Actions": { + "tooltip": "Створити дію на зворотньому боці цього елемента", + "label": "Відкрити панель дії", + "summaryTitle": "Ваші дії", + "title": "Дія" + }, + "DeleteSession": { + "header": "Видалення '{{name}}'?", + "firstLine": "Видалення сесії незворотнє. Він видалить всі записи, голоси, групи та сам сесію. Дані не можна відновити.", + "secondLine": "Ви впевнені у тому, що хочете видалити цю сесію і весь її вміст?", + "yesImSure": "Так, я впевнений", + "cancel": "Ні, вибачте, я помилився" + }, + "RevealCards": { + "buttonLabel": "Показати", + "dialogTitle": "Показати всі карти", + "dialogContent": "Це відкриє для всіх розмиваних карт. Це не може бути скасовано.", + "confirmButton": "Давайте дізнаємося!", + "cancelButton": "Ні, дякую" + }, + "AccountPage": { + "anonymousError": "Анонімні акаунти не можуть мати доступу до свого профілю (адже вони не мають).", + "details": { + "header": "Ваші дані", + "username": "Ім'я користувача", + "email": "Ел. пошта", + "accountType": "Тип облікового запису" + }, + "plan": { + "header": "Ваш План", + "plan": "План", + "youAreOwner": "Ви власник цього плану через нижченаведену підписку.", + "youAreMember": "Ви використовуєте цей тарифний план з чужої підписки." + }, + "subscription": { + "header": "Ваша підписка", + "manageButton": "Керування моєю підпискою", + "membersEditor": { + "title": "Ваша команда", + "limitReached": "Ви досягли ліміту своєї передплати ({{limit}} користувачів, включаючи себе). Будь ласка, вилучіть або оновіть обліковий запис компанії.", + "info": "Додайте листи нижче, щоб надати Pro аккаунтам до {{limit}} інших колег. Натисніть Enter після кожної адреси електронної пошти." + } + }, + "trial": { + "header": "Ваша пробна версія", + "yourTrialWillExpireIn": "Пробний період закінчиться через {{date}}.", + "subscribe": "Підписатися" + }, + "deleteAccount": { + "title": "ҐДРР", + "warning": "Ти маєш право забути. Це сказано, будь обережним, коли видаляєш свій обліковий запис. Це не можна скасувати.", + "deleteData": "Видалити мої дані", + "modal": { + "confirm": { + "title": "Ви абсолютно певні?", + "description": "На цьому немає жодного шляху назад.", + "confirmation": "Так, я хочу видалити всі мої дані", + "cancellation": "Заберіть мене звідси" + }, + "subheader": "Виберіть, що потрібно видалити", + "deleteAccount": "Видаліть обліковий запис і будь-які ідентифікації, що пов'язані з вашою електронною поштою.", + "recommended": "Рекомендовані", + "deleteSessions": { + "main": "Чи слід видалити сесії (створених вами ретроспектив)?", + "selected": "Ваші сеанси і всі їх дані, включно з повідомленнями та голосуваннями інших людей, будуть остаточно видалені.", + "unselected": "Ваші сеанси будуть триматися, а їх автор стане анонімним користувачем." + }, + "deletePosts": { + "main": "Чи повинні ми видалити всі пости, які ти написав?", + "selected": "Ваші повідомлення у будь-якій сесії, а також їх пов'язані голоси та дії будуть назавжди видалені.", + "unselected": "Ваші повідомлення будуть збережені, але вони стануть пов'язаними з анонімним користувачем." + }, + "deleteVotes": { + "main": "Чи варто також видалити всі ваші голоси?", + "selected": "Ваші голоси, по всіх сеансах, буде остаточно видалено.", + "unselected": "Ваші голоси зберігатимуться, але вони стануть пов'язаними з анонімним користувачем." + }, + "deleteAccountButton": "ВИДАЛИТИ ВАШ АКАУНТ", + "cancelButton": "Скасувати" + } + } + }, + "SubscribePage": { + "alertAlreadyPro": "Ви вже є Pro користувачем, тому вам не потрібна інша підписка.", + "alertAlreadySubscribed": "У вас вже є підписка, тому вам не потрібна інша підписка.", + "currency": { + "title": "Валюта", + "description": "Оберіть валюту, з якою ви хотіли б отримувати", + "warning": "Ваш обліковий запис вже налаштовано на використання {{currency}}, тому ви не можете більше змінити валюту." + }, + "plan": { + "title": "План", + "description": "Оберіть план, який відповідає вашому використанню!" + }, + "domain": { + "title": "Домен", + "description": "Ваша необмежена підписка відноситься до даного домену. Будь-який користувач з даного домену електронної пошти автоматично стане користувачем Pro.", + "invalidDomain": "Будь ласка, надайте дійсний домен. Домен не може бути безкоштовним або одноразовим доменом." + }, + "subscribe": { + "title": "Оформити замовлення", + "description": "Вас буде перенаправлено до нашого партнера, Stripe, для оплати", + "cannotRegisterWithAnon": "Щоб продовжити, увійдіть в обліковий запис OAuth або пароль.", + "checkout": "Оформити замовлення" + } + }, + "SubscribeModal": { + "title": "Про-підписка", + "header": "Ретроспективний Про", + "description": "Здійсніть підписку на Retrospeced Pro. З Retrospected Pro, ознайомтеся з наступними функціями та багато іншого:", + "features": { + "encryptedSession": { + "title": "Зашифровані сесії", + "description": "Ваші дані зашифровані в браузері, що робить будь-яке розшифровування неможливим на ретроспективному сервері." + }, + "privateSessions": { + "title": "Приватні сеанси", + "description": "Переконайтеся, що до вашої сесії лише авторизовані люди матимуть доступ тільки до вашого сеансу." + }, + "unlimitedPosts": { + "title": "Необмежені повідомлення", + "description": "З підпискою Pro, отримаєте необмежену кількість повідомлень." + } + }, + "subscribeButton": "Підписатися", + "payButton": "Вибрати", + "cancelButton": "Скасувати", + "startTrial": "30-денне випробування" + }, + "Products": { + "team": "Ідеально підходить для менших груп, ви можете вибрати до 20 колег, які будуть оновлені до Pro аккаунту.", + "unlimited": "Якщо Ви є більшою компанією, Ви отримаєте необмежену кількість Pro аккаунтів.", + "self-hosted": "Відредагується за передумови, одноразову плату та необмежені оновлення. Утримуйте повний контроль над вашими даними, назавжди.", + "users": "{{users}} користувачів", + "unlimited_seats": "Необмежено", + "month": "місяць", + "year": "рік", + "wantToPayYearly": "Я хочу платити щорічно (кожні 12 місяців), та отримати 1 місяць безкоштовно на рік!" + }, + "Encryption": { + "createEncryptedSession": "Зашифрована сесія", + "sessionNotEncrypted": "Ця сесія не зашифрована.", + "sessionEncryptedHaveKeyTooltip": "Ця сесія зашифрована, і ключ зберігається в браузері. Ви можете відкрити цю сесію без необхідності вказати пароль знову.", + "sessionEncryptedNoKeyTooltip": "Ця сесія зашифрована, і ключ не зберігається в браузері. Вам буде запропоновано ключ дешифрування при відкритті цього сесії.", + "sessionEncryptedWrongKeyTooltip": "Ця сесія зашифрована, і вказаний вами ключ є неправильним.", + "newEncryptedSessionWarningTitle": "Ця сесія зашифрована локально", + "newEncryptedSessionWarningContent": "Дуже важливо зберегти повний URL (який містить ключ) де безпечний, або принаймні ключ шифрування: {{key}}. Якщо Ви втратите цей ключ шифрування, то нічого робити не можна буде зробити, щоб отримати дані.", + "sessionEncryptionError": "Ця сесія зашифрована, і у вас немає ключа, який зберігається локально. Будь-ласка, використовуйте оригінальне посилання, включаючи ключ дешифрування.", + "passwordModalTitle": "Зашифрована сесія - Введіть пароль", + "passwordModelIncorrect": "Невірний ключ шифрування." + }, + "Private": { + "lockSuccessNotification": "Ваша сесія була успішно приватною. Нові учасники не можуть приєднатися.", + "unlockSuccessNotification": "Ваша сесія була успішно опублікована. Будь-хто може приєднатися.", + "lockButton": "Зробити приватними", + "unlockButton": "Зробити загальною", + "lockDescription": "Ви збираєтесь зробити сесію приватною. Тільки поточні учасники (перераховані нижче) матимуть доступ до цієї сесії один раз.", + "cancelButton": "Скасувати", + "sessionLockedTitle": "Ця сесія є приватною.", + "sessionLockedDescription": "Будь ласка, попросіть модератора розблокувати його, щоб ви могли приєднатися. Потім оновіть сторінку.", + "sessionNonProTitle": "Ця сесія доступна тільки користувачам Pro", + "sessionNonProDescription": "Ця сесія використовує функції в доступності тільки для зареєстрованих користувачів. Будь ласка, попросіть модератора або власника підписки надати вам обліковий запис Pro.", + "sessionIsPublic": "Ця сесія є публічною і доступною для будь-кого.", + "sessionIsPrivate": "Ця сесія приватна, і у вас є доступ до неї.", + "sessionIsPrivateNoAccess": "Ця сесія приватна, але у вас немає доступу." + }, + "TrialPrompt": { + "allowanceReachedTitle": "Ви досягли своєї безкоштовної кількості", + "allowanceReachedDescription": "Для того, щоб отримати необмежену кількість повідомлень, будь ласка, підпишіться на Retrospected Pro", + "nearEndAllowanceTitle": "Ви наближаєтеся до кінця своєї квоти", + "nearEndAllowanceDescription": "Залишилось {{quota}} відповідей", + "onTrialTitle": "Ретроспективний Pro - Пробна версія", + "remainingTrialSentence": "Ви завершили пробну версію {{remaining}}.", + "trialEndedTitle": "Ваш ретроспективний Pro пробний період закінчився", + "trialEndedSentence": "Підпишіться сьогодні, щоб повернути доступ до можливостей Pro.", + "subscribeNow": "Підписатися зараз!" + }, + "Chat": { + "writeAMessage": "Напишіть повідомлення тут..." + } +} \ No newline at end of file diff --git a/frontend/src/translations/locales/zh-CN.json b/frontend/src/translations/locales/zh-CN.json new file mode 100644 index 000000000..65517fd10 --- /dev/null +++ b/frontend/src/translations/locales/zh-CN.json @@ -0,0 +1,423 @@ +{ + "Header": { + "subtitle": "驾驭敏捷方式的好方法", + "logout": "注销", + "leave": "离开", + "summaryMode": "主旨模式", + "account": "我的帐户", + "adminPanel": "管理面板" + }, + "LanguagePicker": { + "header": "切换语言" + }, + "Main": { + "hint": "复制并分享网址,即可让别人加入此议程" + }, + "Home": { + "welcome": "欢迎, {{name}}" + }, + "PreviousGame": { + "createdBy": "创建者", + "posts_one": "发帖", + "posts_other": "帖子", + "participants_one": "参与者", + "participants_other": "参与者", + "votes_one": "投票", + "votes_other": "投票", + "actions_one": "行动", + "actions_other": "操作" + }, + "Column": { + "createGroupTooltip": "创建一个群组将帖子一起分组" + }, + "Group": { + "emptyGroupTitle": "这是一个空组", + "emptyGroupContent": "将一个帖子移动到这里来填写此组" + }, + "Post": { + "openExtra": "附加功能", + "closeExtra": "关闭", + "vote": "投票", + "votes": "表决", + "deleteButton": "删除", + "setActionButton": "设置操作", + "setGiphyButton": "选择一个Giphy 图像", + "noContent": "(目前无任何内容)", + "by": "由", + "upVote": "向上投票", + "downVote": "投反对票", + "voteRemainingMultiple": "您还剩下了 {{number}} {{type}}秒。", + "voteRemainingOne": "你只剩下一个 {{type}} ,把它算进去!", + "voteRemainingNone": "您没有剩余任何 {{type}}。", + "toggleGiphyButton": "切换Giphy图像" + }, + "Customize": { + "title": "自定义您的会话", + "votingCategory": "表 决", + "votingCategorySub": "设置关于喜欢和不喜欢的规则", + "postCategory": "帖子设置", + "postCategorySub": "设置用户在创建或查看帖子时可以做什么的规则", + "customTemplateCategory": "列模板", + "customTemplateCategorySub": "设置列数及其特性", + "startButton": "开始会话", + "editButton": "更新", + "maxUpVotes": "最大向上投票数", + "maxUpVotesHelp": "允许用户投出的最大“喜欢”票数", + "maxDownVotes": "最大投票数", + "maxDownVotesHelp": "允许用户投出的最大“不喜欢”票数", + "maxPosts": "每个用户的最大帖子", + "maxPostsHelp": "每个用户可以创建的帖子的最大数量", + "allowSelfVoting": "允许自己投票", + "allowSelfVotingHelp": "是否允许用户对自己的帖子投票", + "allowMultipleVotes": "允许多个投票", + "allowMultipleVotesHelp": "是否允许用户在同一个帖子上多次投票", + "allowActions": "允许操作", + "allowActionsHelp": "是否允许每个帖子上的“动作”(后续)", + "allowAuthorVisible": "显示作者", + "allowAuthorVisibleHelp": "在帖子本身上显示帖子的作者。", + "newPostsFirst": "先添加新帖子", + "newPostsFirstHelp": "在列顶部添加新帖子", + "allowGiphy": "允许Giphy", + "allowGiphyHelp": "允许用户根据帖子设置Giphy 图像", + "allowGrouping": "允许分组", + "allowGroupingHelp": "允许创建群组将帖子一起分组", + "allowReordering": "允许重新排序", + "allowReorderingHelp": "允许通过拖放重新排序帖子", + "blurCards": "模糊卡", + "blurCardsHelp": "在版主显示内容之前,卡片内容是模糊的", + "template": "模板", + "templateHelp": "使用预定义的列集", + "numberOfColumns": "列数", + "numberOfColumnsHelp": "设置列数", + "makeDefaultTemplate": "将此设置为我的默认模板" + }, + "PostBoard": { + "customQuestion": "自定义列", + "notWellQuestion": "哪些已经改善?", + "wellQuestion": "哪些做的很好?", + "ideasQuestion": "分享优秀的点子?", + "startQuestion": "开始", + "stopQuestion": "停止", + "continueQuestion": "继续", + "likedQuestion": "赞的", + "lackedQuestion": "已打包", + "learnedQuestion": "学习", + "longedForQuestion": "延时", + "anchorQuestion": "锚点", + "boatQuestion": "小船", + "islandQuestion": "岛", + "windQuestion": "向导", + "rockQuestion": "摇动", + "disconnected": "您已与当前会话断开连接。", + "reconnect": "重新连接", + "notLoggedIn": "您尚未登录。您可以将此会话视为旁观者,但必须登录才能参与。", + "error_action_unauthorised": "您无权执行此操作。", + "error_cannot_edit_group": "编辑组失败。", + "error_cannot_edit_post": "编辑帖子失败。", + "error_cannot_get_session": "无法获取会话数据。请重新加载页面。", + "error_cannot_register_vote": "您的投票未成功注册。", + "error_cannot_save_group": "无法保存您创建的组。", + "error_cannot_save_post": "您创建的帖子无法保存。", + "error_cannot_delete_group": "群组无法删除", + "error_cannot_delete_post": "帖子无法删除", + "error_cannot_rename_session": "重命名会话失败", + "error_cannot_save_columns": "保存列失败", + "error_cannot_save_options": "保存选项失败", + "maxPostsReached": "您已经达到了版主设置的帖子的最大数量。", + "iAmDone": "我已完成!", + "iAmNotDoneYet": "我还没有完成...", + "userIsReady": "{{user}} 已准备好了!" + }, + "GameMenu": { + "board": "棋盘", + "summary": "Summary" + }, + "Template": { + "default": "默认设置", + "wellNotWell": "好的 / 不好", + "startStopContinue": "开始/停止/继续", + "fourLs": "四指示灯", + "sailboat": "帆船" + }, + "Clients": { + "header": "已加入我们的:", + "joined": "{{users}} 已加入。", + "left": "{{users}} 离开了。" + }, + "Join": { + "welcome": "欢迎 Retrospected", + "standardTab": { + "header": "创建", + "text": "点击以下开始进行回顾:", + "button": "创建新的议程", + "customizeButton": "自定义" + }, + "optionsTab": { + "header": "高级设定", + "input": "名称", + "button": "创建议程" + }, + "previousTab": { + "header": "之前的议程", + "rejoinButton": "再次加入" + } + }, + "AnonymousLogin": { + "namePlaceholder": "您是谁? 在此输入您的名称", + "buttonLabel": "开始!", + "header": "登录", + "anonymousAuthHeader": "匿名登录", + "anonymousAuthDescription": "这将创建一个匿名帐户。有些功能将不可用。", + "authenticatingWith": "正在验证", + "or": "或" + }, + "SocialMediaLogin": { + "header": "OAuth", + "info": "这将使用您选择的第三方提供商来验证您。没有密码已保存。" + }, + "AuthCommon": { + "emailField": "电子邮箱", + "passwordField": "密码", + "nameField": "您的名字(用于显示目的)", + "passwordScoreWords": [ + "脆弱的", + "脆弱的", + "不好", + "很好", + "强度" + ] + }, + "AccountLogin": { + "header": "密码", + "loginButton": "登录", + "info": "使用您的电子邮件和密码登录。", + "registerLink": "未注册?点击这里", + "forgotPasswordLink": "忘记密码?", + "errorEmailPasswordIncorrect": "您的凭据不正确。" + }, + "Register": { + "header": "注册", + "info": "给自己一个回归账户!", + "registerButton": "注册", + "errorAlreadyRegistered": "此电子邮件已注册", + "errorGeneral": "尝试创建您的帐户时出错。", + "messageSuccess": "谢谢!您将很快收到一封电子邮件来验证您的帐户。", + "errorInvalidEmail": "请输入一个有效的电子邮件" + }, + "ValidateAccount": { + "success": "您的电子邮件已被正确验证。我将登录一个秒钟!", + "error": "验证您的电子邮件时出错。", + "loading": "我们正在验证您的电子邮件。请稍候。" + }, + "ResetPassword": { + "doneMessage": "完成了!看看您的电子邮件,您应该有一个重置密码的链接。", + "header": "密码重置", + "resetButton": "重置密码", + "info": "忘记密码?不会出现问题。请在下方输入您的电子邮件,然后您会收到重置电子邮件提示。", + "success": "您的密码已经更新。我将登录一会儿!", + "error": "更新您的密码时出错。", + "loading": "我们正在更新您的密码。请稍候。", + "resetInfo": "请提供新密码" + }, + "SummaryBoard": { + "noPosts": "目前无任何内容", + "copyAsMarkdown": "将摘要复制为Markdown", + "copyAsRichText": "复制摘要为富文本", + "copySuccessful": "您已成功复制您的摘要到剪贴板" + }, + "SessionName": { + "defaultSessionName": "我的回顾" + }, + "Invite": { + "inviteButton": "邀请", + "dialog": { + "title": "邀请别人来到您的议程", + "text": "邀请别人来到您的议程,只要分享以下的网址给他们", + "copyButton": "复制网址到剪贴簿" + } + }, + "Generic": { + "ok": "好的", + "cancel": "取消" + }, + "Actions": { + "tooltip": "在此项目的背面创建一个操作", + "label": "打开“操作”面板", + "summaryTitle": "你的行动", + "title": "行动" + }, + "DeleteSession": { + "header": "正在删除 '{{name}} ' 吗?", + "firstLine": "删除会话是不可逆的。它将删除所有帖子、投票、组和会话本身。数据无法恢复。", + "secondLine": "您确定要删除此会话及其所有内容吗?", + "yesImSure": "是的,我确定", + "cancel": "不,对不起,我犯了一个错误" + }, + "RevealCards": { + "buttonLabel": "显示", + "dialogTitle": "显示所有卡片", + "dialogContent": "这将显示所有人的模糊卡片。无法撤消。", + "confirmButton": "让我们揭示!", + "cancelButton": "不要谢谢。" + }, + "AccountPage": { + "anonymousError": "匿名帐户不能访问他们的个人资料 (因为他们没有一个)。", + "details": { + "header": "您的详细信息", + "username": "用户名", + "email": "电子邮件地址", + "accountType": "帐户类型" + }, + "plan": { + "header": "您的计划", + "plan": "计划", + "youAreOwner": "您是此计划的所有者,通过下面的订阅。", + "youAreMember": "您正在通过其他人的订阅加入此计划。" + }, + "subscription": { + "header": "您的订阅", + "manageButton": "管理我的订阅", + "membersEditor": { + "title": "您的团队", + "limitReached": "您的订阅已达到极限({{limit}} 用户,包括您自己)。请删除会员,或升级到无限公司帐户。", + "info": "在下面添加电子邮件,给予最多 {{limit}} 位其他同事专业版帐户。在每个电子邮件地址后按回车键。" + } + }, + "trial": { + "header": "您的测试", + "yourTrialWillExpireIn": "您的试用版将在 {{date}} 后结束。", + "subscribe": "现在订阅" + }, + "deleteAccount": { + "title": "GDPR", + "warning": "您有权被遗忘。虽然这么说,在删除您的帐户时要小心。这不能撤消。", + "deleteData": "删除我的数据", + "modal": { + "confirm": { + "title": "您是否绝对确定?", + "description": "在这个问题上没有回来。", + "confirmation": "是的,我想要删除我的所有数据", + "cancellation": "让我离开这里" + }, + "subheader": "选择要删除的内容", + "deleteAccount": "删除您的帐户和与您的电子邮件链接的任何身份。", + "recommended": "推荐的", + "deleteSessions": { + "main": "我们是否应该删除您创建的会话 (追溯) ?", + "selected": "您的会议和他们的所有数据,包括其他人的帖子和投票,将被永久删除。", + "unselected": "您的会话将被保存,其作者将成为匿名用户。" + }, + "deletePosts": { + "main": "我们是否应该删除你写过的所有帖子?", + "selected": "您在任何会话中的帖子及其相关的投票和动作将被永久删除。", + "unselected": "您的帖子将被保留,但他们将与匿名用户关联。" + }, + "deleteVotes": { + "main": "我们是否也要删除您所有的投票?", + "selected": "您的投票将在所有会话中被永久删除。", + "unselected": "您的投票将被保留,但他们将与匿名用户关联。" + }, + "deleteAccountButton": "删除您的帐户", + "cancelButton": "取消" + } + } + }, + "SubscribePage": { + "alertAlreadyPro": "您已经是专业版用户,所以您可能不需要其他订阅。", + "alertAlreadySubscribed": "您已经有一个订阅,所以您可能不需要另一个订阅。", + "currency": { + "title": "货币", + "description": "选择您想要计费的货币", + "warning": "您的帐户已设置为 {{currency}},因此您不能再更改货币。" + }, + "plan": { + "title": "计划", + "description": "选择适合您使用情况的计划!" + }, + "domain": { + "title": "域", + "description": "您的无限订阅适用于指定的域。任何使用此电子邮件域的用户都将自动成为专业版用户。", + "invalidDomain": "请提供一个有效的域。该域不能是一个免费或可用的电子邮件域。" + }, + "subscribe": { + "title": "签出", + "description": "您将被重定向到我们的合伙人,Stripe以便付款", + "cannotRegisterWithAnon": "您需要使用 OAuth 或密码帐户登录才能继续。", + "checkout": "签出" + } + }, + "SubscribeModal": { + "title": "Pro 订阅", + "header": "回顾专业版", + "description": "通过订阅Retrospected Pro来保护您的公司数据。使用Retrospected Pro,获得以下功能和更多功能:", + "features": { + "encryptedSession": { + "title": "加密会话", + "description": "您的数据被加密在您的浏览器中,从而使得任何解密都无法在返回服务器上进行。" + }, + "privateSessions": { + "title": "私人会话", + "description": "请确保只有授权的人可以访问您的会话。" + }, + "unlimitedPosts": { + "title": "无限帖子", + "description": "通过专业版订阅,获得无限的帖子。" + } + }, + "subscribeButton": "订阅", + "payButton": "选择", + "cancelButton": "取消", + "startTrial": "30天测试" + }, + "Products": { + "team": "适合较小的团队,您可以选择最多20个同事升级到专业版帐户。", + "unlimited": "如果您是一个较大的公司,您将享受无限数量的专业版账户。", + "self-hosted": "回到房地,一次性收费和无限制的更新。始终保持对您数据的完全控制。", + "users": "{{users}} 位用户", + "unlimited_seats": "无限制", + "month": "月", + "year": "年", + "wantToPayYearly": "我想每年支付一次(每12个月),每年免费支付一个月!" + }, + "Encryption": { + "createEncryptedSession": "加密会话", + "sessionNotEncrypted": "此会话未加密。", + "sessionEncryptedHaveKeyTooltip": "此会话已加密,密钥已保存在您的浏览器中。您可以打开此会话而不必再次提供密码。", + "sessionEncryptedNoKeyTooltip": "此会话已加密,密钥未保存在您的浏览器中。在打开此会话时,您将被要求输入解密密钥。", + "sessionEncryptedWrongKeyTooltip": "此会话已加密,您存储的密钥不是正确的密钥。", + "newEncryptedSessionWarningTitle": "此会话是本地加密", + "newEncryptedSessionWarningContent": "非常重要的是,您可以在安全的地方保存完整的 URL (包含密钥)。 或至少加密密钥: {{key}}如果您丢失了此加密密钥,则无法检索数据。", + "sessionEncryptionError": "此会话已加密,您似乎没有本地解密密钥。请使用原始链接,包括解密密钥。", + "passwordModalTitle": "加密会话 - 输入密码", + "passwordModelIncorrect": "加密密钥不正确。" + }, + "Private": { + "lockSuccessNotification": "您的会话已成功私有。没有新的参与者可以加入。", + "unlockSuccessNotification": "您的会话已成功发布。任何人都可以加入。", + "lockButton": "设为私人的", + "unlockButton": "公开设置", + "lockDescription": "您将要将会话变为隐私。只允许当前的参与者 (下面列出)在锁定后访问此会话。", + "cancelButton": "取消", + "sessionLockedTitle": "此会话是私密的。", + "sessionLockedDescription": "请让其版主解锁它,以便您可以加入,然后刷新此页面。", + "sessionNonProTitle": "此会话仅供专业版用户访问", + "sessionNonProDescription": "此会话只使用专业版用户可用的功能。请联系人或订阅者给您一个专业版账户。", + "sessionIsPublic": "此会话是公开的,任何人都可以访问。", + "sessionIsPrivate": "此会话是私密的,您可以访问。", + "sessionIsPrivateNoAccess": "此会话是私密的,但您没有访问权限。" + }, + "TrialPrompt": { + "allowanceReachedTitle": "您已达到免费津贴", + "allowanceReachedDescription": "为了获得无限的帖子,请订阅Retrospected Pro", + "nearEndAllowanceTitle": "您的配额即将结束", + "nearEndAllowanceDescription": "您还剩下了大约 {{quota}} 个帖子", + "onTrialTitle": "回忆Pro - 测试", + "remainingTrialSentence": "您的试用版还有 {{remaining}}。", + "trialEndedTitle": "您的回忆专业版试用已结束", + "trialEndedSentence": "今天订阅以重新获得专业版功能。", + "subscribeNow": "现在订阅 !" + }, + "Chat": { + "writeAMessage": "在此处写一条消息..." + } +} \ No newline at end of file diff --git a/frontend/src/translations/locales/zh-TW.json b/frontend/src/translations/locales/zh-TW.json new file mode 100644 index 000000000..b8e4da7b2 --- /dev/null +++ b/frontend/src/translations/locales/zh-TW.json @@ -0,0 +1,423 @@ +{ + "Header": { + "subtitle": "駕馭敏捷方式的好方法", + "logout": "登出", + "leave": "離開", + "summaryMode": "主旨模式", + "account": "我的賬戶", + "adminPanel": "管理面板" + }, + "LanguagePicker": { + "header": "切換語言" + }, + "Main": { + "hint": "複製並分享網址,即可讓別人加入此議程" + }, + "Home": { + "welcome": "歡迎, {{name}}" + }, + "PreviousGame": { + "createdBy": "由...製作", + "posts_one": "郵政", + "posts_other": "帖子", + "participants_one": "參與者", + "participants_other": "參與者", + "votes_one": "投票", + "votes_other": "選票", + "actions_one": "行動", + "actions_other": "行動" + }, + "Column": { + "createGroupTooltip": "創建組以將帖子分組在一起" + }, + "Group": { + "emptyGroupTitle": "這是一個空組", + "emptyGroupContent": "將帖子移至此處以填充此組" + }, + "Post": { + "openExtra": "附加的功能", + "closeExtra": "關閉", + "vote": "投票", + "votes": "表決", + "deleteButton": "刪除", + "setActionButton": "設置動作", + "setGiphyButton": "選擇一個 Giphy 圖像", + "noContent": "(目前無任何內容)", + "by": "經過", + "upVote": "贊成票", + "downVote": "否決票", + "voteRemainingMultiple": "您還剩 {{number}} {{type}}秒。", + "voteRemainingOne": "你只剩下一個 {{type}} 了,算了吧!", + "voteRemainingNone": "你沒有任何剩餘的 {{type}}。", + "toggleGiphyButton": "切換 Giphy 圖像" + }, + "Customize": { + "title": "自定義您的會話", + "votingCategory": "表決", + "votingCategorySub": "設定好惡規則", + "postCategory": "帖子設置", + "postCategorySub": "設置用戶在創建或查看帖子時可以做什麼的規則", + "customTemplateCategory": "列模板", + "customTemplateCategorySub": "設置列數及其特徵", + "startButton": "開始會話", + "editButton": "更新", + "maxUpVotes": "最大投票數", + "maxUpVotesHelp": "允許用戶投的“喜歡”投票的最大數量", + "maxDownVotes": "最大反對票", + "maxDownVotesHelp": "允許用戶投的“不喜歡”投票的最大數量", + "maxPosts": "每個用戶的最大帖子數", + "maxPostsHelp": "用戶每個會話可以創建的最大帖子數", + "allowSelfVoting": "允許自我投票", + "allowSelfVotingHelp": "是否允許用戶對自己的帖子進行投票", + "allowMultipleVotes": "允許多票", + "allowMultipleVotesHelp": "是否允許用戶對同一個帖子進行多次投票", + "allowActions": "允許操作", + "allowActionsHelp": "是否允許每個帖子上的“操作”(跟進)字段", + "allowAuthorVisible": "顯示作者", + "allowAuthorVisibleHelp": "在帖子本身上顯示帖子的作者。", + "newPostsFirst": "首先添加新帖子", + "newPostsFirstHelp": "新帖子添加在列的頂部", + "allowGiphy": "允許 Giphy", + "allowGiphyHelp": "允許用戶針對帖子設置 Giphy 圖像", + "allowGrouping": "允許分組", + "allowGroupingHelp": "允許創建組以將帖子分組在一起", + "allowReordering": "允許重新訂購", + "allowReorderingHelp": "允許通過拖放重新排序帖子", + "blurCards": "模糊卡片", + "blurCardsHelp": "卡片內容模糊,直到版主顯示內容", + "template": "模板", + "templateHelp": "使用一組預定義的列", + "numberOfColumns": "列數", + "numberOfColumnsHelp": "設置列數", + "makeDefaultTemplate": "將此作為我的默認模板" + }, + "PostBoard": { + "customQuestion": "自定義列", + "notWellQuestion": "哪些已經改善?", + "wellQuestion": "哪些做的很好?", + "ideasQuestion": "分享優秀的點子?", + "startQuestion": "開始", + "stopQuestion": "停止", + "continueQuestion": "繼續", + "likedQuestion": "喜歡", + "lackedQuestion": "缺乏", + "learnedQuestion": "學到了", + "longedForQuestion": "渴望", + "anchorQuestion": "錨", + "boatQuestion": "船", + "islandQuestion": "島", + "windQuestion": "風", + "rockQuestion": "岩石", + "disconnected": "您已與當前會話斷開連接。", + "reconnect": "重新連接", + "notLoggedIn": "您尚未登錄。您可以作為旁觀者查看此會話,但必須登錄才能參與。", + "error_action_unauthorised": "您無權執行此操作。", + "error_cannot_edit_group": "編輯組失敗。", + "error_cannot_edit_post": "編輯帖子失敗。", + "error_cannot_get_session": "無法獲取會話數據。請重新加載頁面。", + "error_cannot_register_vote": "您的投票未成功登記。", + "error_cannot_save_group": "您創建的群組無法保存。", + "error_cannot_save_post": "您創建的帖子無法保存。", + "error_cannot_delete_group": "無法刪除群組", + "error_cannot_delete_post": "無法刪除帖子", + "error_cannot_rename_session": "重命名會話失敗", + "error_cannot_save_columns": "保存列失敗", + "error_cannot_save_options": "保存選項失敗", + "maxPostsReached": "您已達到版主設置的最大帖子數。", + "iAmDone": "我受夠了!", + "iAmNotDoneYet": "我還沒搞定...", + "userIsReady": "{{user}} 準備好了!" + }, + "GameMenu": { + "board": "木板", + "summary": "概括" + }, + "Template": { + "default": "默認", + "wellNotWell": "好/不好", + "startStopContinue": "開始/停止/繼續", + "fourLs": "四個 L", + "sailboat": "帆船" + }, + "Clients": { + "header": "已加入我們的:", + "joined": "{{users}} 人加入。", + "left": "還剩{{users}} 個。" + }, + "Join": { + "welcome": "歡迎 Retrospected", + "standardTab": { + "header": "新增", + "text": "點擊以下開始進行回顧:", + "button": "建立新的議程", + "customizeButton": "定制" + }, + "optionsTab": { + "header": "進階設定", + "input": "名稱", + "button": "建立議程" + }, + "previousTab": { + "header": "之前的議程", + "rejoinButton": "再次加入" + } + }, + "AnonymousLogin": { + "namePlaceholder": "您是誰? 在此輸入您的名稱", + "buttonLabel": "開始!", + "header": "登錄", + "anonymousAuthHeader": "匿名登錄", + "anonymousAuthDescription": "這將創建一個匿名帳戶。某些功能將不可用。", + "authenticatingWith": "身份驗證", + "or": "或者" + }, + "SocialMediaLogin": { + "header": "身份驗證", + "info": "這將使用您選擇的第三方提供商對您進行身份驗證。沒有存儲密碼。" + }, + "AuthCommon": { + "emailField": "電子郵件", + "passwordField": "密碼", + "nameField": "您的姓名(用於顯示目的)", + "passwordScoreWords": [ + "虛弱的", + "虛弱的", + "不完全的", + "好的", + "強的" + ] + }, + "AccountLogin": { + "header": "密碼", + "loginButton": "登錄", + "info": "使用您的電子郵件和密碼登錄。", + "registerLink": "沒有註冊?點擊這裡", + "forgotPasswordLink": "忘記密碼了嗎?", + "errorEmailPasswordIncorrect": "您的憑據不正確。" + }, + "Register": { + "header": "登記", + "info": "給自己一個追溯賬戶!", + "registerButton": "登記", + "errorAlreadyRegistered": "此郵箱號已被註冊", + "errorGeneral": "嘗試創建您的帳戶時出錯。", + "messageSuccess": "謝謝!您應該很快會收到一封電子郵件以驗證您的帳戶。", + "errorInvalidEmail": "請輸入有效電子郵件" + }, + "ValidateAccount": { + "success": "您的電子郵件已正確驗證。我會在幾秒鐘內讓你登錄!", + "error": "驗證您的電子郵件時出錯。", + "loading": "我們正在驗證您的電子郵件。請稍等。" + }, + "ResetPassword": { + "doneMessage": "完畢!查看您的電子郵件,您應該會獲得重置密碼的鏈接。", + "header": "重設密碼", + "resetButton": "重設密碼", + "info": "忘記密碼了嗎?不是問題。在下方輸入您的電子郵件,您將收到重置電子郵件提示。", + "success": "您的密碼已更新。我會在幾秒鐘內讓你登錄!", + "error": "更新您的密碼時出錯。", + "loading": "我們正在更新您的密碼。請稍等。", + "resetInfo": "請提供新密碼" + }, + "SummaryBoard": { + "noPosts": "目前無任何內容", + "copyAsMarkdown": "將摘要復制為 Markdown", + "copyAsRichText": "將摘要復制為富文本", + "copySuccessful": "您已成功將摘要復製到剪貼板" + }, + "SessionName": { + "defaultSessionName": "我的回顧" + }, + "Invite": { + "inviteButton": "邀請", + "dialog": { + "title": "邀請別人來到您的議程", + "text": "邀請別人來到您的議程,只要分享以下的網址給他們", + "copyButton": "複製網址到剪貼簿" + } + }, + "Generic": { + "ok": "好的", + "cancel": "取消" + }, + "Actions": { + "tooltip": "在此項目的背面創建一個操作", + "label": "打開“操作”面板", + "summaryTitle": "你的行動", + "title": "行動" + }, + "DeleteSession": { + "header": "刪除“{{name}}”?", + "firstLine": "刪除會話是不可逆的。它將刪除所有帖子、投票、組和會話本身。數據無法恢復。", + "secondLine": "您確定要刪除此會話及其所有內容嗎?", + "yesImSure": "是,我確定", + "cancel": "不,對不起,我弄錯了" + }, + "RevealCards": { + "buttonLabel": "揭示", + "dialogTitle": "顯示所有卡片", + "dialogContent": "這將為每個人顯示所有模糊的卡片。這不能被撤消。", + "confirmButton": "讓我們揭曉!", + "cancelButton": "不,謝謝" + }, + "AccountPage": { + "anonymousError": "匿名帳戶無法訪問他們的個人資料(因為他們沒有個人資料)。", + "details": { + "header": "你的資料", + "username": "用戶名", + "email": "電子郵件", + "accountType": "帳戶類型" + }, + "plan": { + "header": "你的計劃", + "plan": "計劃", + "youAreOwner": "通過以下訂閱,您是該計劃的所有者。", + "youAreMember": "您通過其他人的訂閱參與此計劃。" + }, + "subscription": { + "header": "您的訂閱", + "manageButton": "管理我的訂閱", + "membersEditor": { + "title": "你的團隊", + "limitReached": "您已達到訂閱限制({{limit}} 個用戶,包括您自己)。請刪除成員,或升級到無限制的公司帳戶。", + "info": "在下方添加電子郵件以將 Pro 帳戶授予最多 {{limit}} 位其他同事。在每個電子郵件地址後按 Enter。" + } + }, + "trial": { + "header": "您的試用", + "yourTrialWillExpireIn": "您的試用期將以 {{date}}結束。", + "subscribe": "現在訂閱" + }, + "deleteAccount": { + "title": "GDPR", + "warning": "你有權被遺忘。話雖如此,刪除帳戶時要小心。這不能被撤消。", + "deleteData": "刪除我的數據", + "modal": { + "confirm": { + "title": "你絕對確定嗎?", + "description": "沒有回頭路。", + "confirmation": "是的,我想刪除我的所有數據", + "cancellation": "帶我離開這裡" + }, + "subheader": "選擇要刪除的內容", + "deleteAccount": "刪除您的帳戶以及與您的電子郵件相關聯的任何身份。", + "recommended": "受到推崇的", + "deleteSessions": { + "main": "我們應該刪除您創建的會議(回顧)嗎?", + "selected": "您的會話及其所有數據,包括其他人的帖子和投票,將被永久刪除。", + "unselected": "您的會話將被保留,其作者將成為匿名用戶。" + }, + "deletePosts": { + "main": "我們應該刪除你寫的所有帖子嗎?", + "selected": "您在任何會話中的帖子及其相關投票和操作都將被永久刪除。", + "unselected": "您的帖子將被保留,但它們將與匿名用戶相關聯。" + }, + "deleteVotes": { + "main": "我們是否也應該刪除您的所有選票?", + "selected": "您在所有會話中的投票將被永久刪除。", + "unselected": "您的投票將被保留,但它們將與匿名用戶相關聯。" + }, + "deleteAccountButton": "刪除您的帳戶", + "cancelButton": "取消" + } + } + }, + "SubscribePage": { + "alertAlreadyPro": "您已經是 Pro 用戶,因此您可能不需要其他訂閱。", + "alertAlreadySubscribed": "您已經有訂閱,因此您可能不需要其他訂閱。", + "currency": { + "title": "貨幣", + "description": "選擇一種您想要結算的貨幣", + "warning": "您的帳戶已設置為使用 {{currency}},因此您無法再更改貨幣。" + }, + "plan": { + "title": "計劃", + "description": "選擇適合您用例的計劃!" + }, + "domain": { + "title": "領域", + "description": "您的無限制訂閱適用於給定域。擁有此電子郵件域的任何用戶都將自動成為 Pro 用戶。", + "invalidDomain": "請提供一個有效的域。該域不能是免費或一次性電子郵件域。" + }, + "subscribe": { + "title": "查看", + "description": "您將被重定向到我們的合作夥伴 Stripe 進行付款", + "cannotRegisterWithAnon": "您需要使用 OAuth 或密碼帳戶登錄才能繼續。", + "checkout": "查看" + } + }, + "SubscribeModal": { + "title": "專業訂閱", + "header": "回顧專業版", + "description": "通過訂閱 Retrospected Pro 來保護您公司的數據。使用 Retrospected Pro,獲得以下功能及更多:", + "features": { + "encryptedSession": { + "title": "加密會話", + "description": "您的數據在您的瀏覽器中被加密,因此無法在 Retrospected 服務器上進行任何解密。" + }, + "privateSessions": { + "title": "私人會議", + "description": "確保只有經過授權的人才能訪問您的會話。" + }, + "unlimitedPosts": { + "title": "無限帖子", + "description": "通過 Pro 訂閱,獲得無限的帖子。" + } + }, + "subscribeButton": "訂閱", + "payButton": "選擇", + "cancelButton": "取消", + "startTrial": "30 天試用" + }, + "Products": { + "team": "非常適合小型團隊,您最多可以選擇 20 位同事升級為 Pro 帳戶。", + "unlimited": "如果您是一家更大的公司,您將享受無限數量的 Pro 帳戶。", + "self-hosted": "現場回顧、一次性費用和無限更新。永遠完全控制您的數據。", + "users": "{{users}} 個用戶", + "unlimited_seats": "無限", + "month": "月", + "year": "年", + "wantToPayYearly": "我想按年付款(每 12 個月),每年免費獲得一個月!" + }, + "Encryption": { + "createEncryptedSession": "加密會話", + "sessionNotEncrypted": "此會話未加密。", + "sessionEncryptedHaveKeyTooltip": "此會話已加密,密鑰存儲在您的瀏覽器中。您無需再次提供密碼即可打開此會話。", + "sessionEncryptedNoKeyTooltip": "此會話已加密,密鑰未存儲在您的瀏覽器中。打開此會話時,您將被要求提供解密密鑰。", + "sessionEncryptedWrongKeyTooltip": "此會話已加密,您存儲的密鑰不是正確的密鑰。", + "newEncryptedSessionWarningTitle": "此會話在本地加密", + "newEncryptedSessionWarningContent": "將完整的 URL(包含密鑰)保存在安全的地方,或者至少是加密密鑰: {{key}}對您來說非常重要。如果丟失此加密密鑰,則無法檢索數據。", + "sessionEncryptionError": "此會話已加密,您似乎沒有本地存儲解密密鑰。請使用原始鏈接,包括解密密鑰。", + "passwordModalTitle": "加密會話 - 輸入密碼", + "passwordModelIncorrect": "加密密鑰不正確。" + }, + "Private": { + "lockSuccessNotification": "您的會話已成功設為私有。沒有新的參與者可以加入。", + "unlockSuccessNotification": "您的會話已成功公開。任何人都可以加入。", + "lockButton": "設為私有", + "unlockButton": "公開", + "lockDescription": "您即將將會話設為私有。鎖定後,只有當前參與者(如下所列)才能訪問此會話。", + "cancelButton": "取消", + "sessionLockedTitle": "本次會議是私人的。", + "sessionLockedDescription": "請要求其版主解鎖,以便您加入。然後,刷新此頁面。", + "sessionNonProTitle": "此會話僅供專業用戶訪問", + "sessionNonProDescription": "此會話使用僅適用於 Pro 用戶的功能。請要求版主或訂閱持有人給您一個 Pro 帳戶。", + "sessionIsPublic": "此會話是公開的,任何人都可以訪問。", + "sessionIsPrivate": "此會話是私人的,您可以訪問。", + "sessionIsPrivateNoAccess": "此會話是私人的,但您無權訪問。" + }, + "TrialPrompt": { + "allowanceReachedTitle": "您已達到免費限額", + "allowanceReachedDescription": "為了獲得無限的帖子,請訂閱 Retrospected Pro", + "nearEndAllowanceTitle": "您的配額即將用完", + "nearEndAllowanceDescription": "您還剩大約 {{quota}} 個帖子", + "onTrialTitle": "Retrospected Pro - 試用版", + "remainingTrialSentence": "您的試用期還剩 {{remaining}} 個。", + "trialEndedTitle": "您的 Retrospected Pro 試用已結束", + "trialEndedSentence": "立即訂閱以重新獲得對 Pro 功能的訪問權限。", + "subscribeNow": "現在訂閱!" + }, + "Chat": { + "writeAMessage": "在這裡寫留言..." + } +} \ No newline at end of file diff --git a/frontend/src/translations/nl.ts b/frontend/src/translations/nl.ts deleted file mode 100644 index 7d425571f..000000000 --- a/frontend/src/translations/nl.ts +++ /dev/null @@ -1,416 +0,0 @@ -import { Translation } from './types'; -import { plural } from './utils'; -export default { - Header: { - subtitle: 'Een goede manier om in een gestructureerde manier te tieren', - logout: 'Afmelden', - leave: 'Verlaten', - summaryMode: 'Samenvatting', - account: undefined, - adminPanel: undefined, - }, - LanguagePicker: { - header: 'Kies een taal', - }, - Main: { - hint: 'Je kan anderen uitnodigen voor deze sessie door de URL te kopiëren en te plakken', - }, - Home: { - welcome: (userName: string) => `Welkom, ${userName}`, - }, - PreviousGame: { - createdBy: 'Aangemaakt door', - posts: plural('post'), - participants: plural('deelnemer'), - votes: plural('stem', 'stemmen'), - actions: plural('actie'), - }, - Column: { - createGroupTooltip: 'Creeër een groep om retropunten te bundelen', - }, - Group: { - emptyGroupTitle: 'Dit is een lege groep', - emptyGroupContent: - 'Verplaats een retropunt hierheen om deze groep te vullen', - }, - Post: { - openExtra: 'Extra features', - closeExtra: 'Sluiten', - vote: 'Stem', - votes: 'Stemmen', - deleteButton: 'Verwijderen', - setActionButton: 'Instellen actie', - setGiphyButton: 'Kies een Giphy afbeelding', - noContent: '(Dit retropunt heeft geen inhoud)', - by: 'door', - upVote: 'up-vote', - downVote: 'down-vote', - voteRemainingMultiple: (count: number, type: string) => - `Je hebt ${count} ${type}s over.`, - voteRemainingOne: (type: string) => - `Je hebt nog maar ${type} over, zorg dat hij telt!`, - voteRemainingNone: (type: string) => `Je hebt geen ${type} over.`, - toggleGiphyButton: 'Aan- en uitschakelen Giphy afbeelding', - }, - Customize: { - title: 'Sessie aanpassen', - votingCategory: 'Stemmen', - votingCategorySub: 'Instellen regels voor stemmen', - postCategory: 'Retropunten instellingen', - postCategorySub: - 'Instellen regels wat een gebruiker kan doen wanneer hij reageert op een retropunt', - customTemplateCategory: 'Kolommen template', - customTemplateCategorySub: 'Instellen aantal kolommen en hun specificaties', - startButton: 'Start de sessie', - maxUpVotes: 'Maximum up-votes', - maxUpVotesHelp: `Maximum aantal 'likes' die een gebruiker mag uitbrengen`, - maxDownVotes: 'Maximum down-votes', - maxDownVotesHelp: `Maximum aantal 'dislikes' die een gebruiker mag uitbrengen`, - maxPosts: undefined, - maxPostsHelp: undefined, - allowSelfVoting: 'Zelf-stemmen toestaan', - allowSelfVotingHelp: - 'Of een gebruiker op zijn eigen retropunten mag stemmen', - allowMultipleVotes: 'Meerdere stemmen toestaan', - allowMultipleVotesHelp: - 'Of een gebruiker meerdere stemmen op hetzelfde retropunt kan uitbrengen', - allowActions: 'Acties toestaan', - allowActionsHelp: `Toestaan van 'Acties' veld (follow-up) op elk retropunt`, - allowAuthorVisible: 'Toon auteur', - allowAuthorVisibleHelp: 'Tonen van auteur op het retropunt.', - newPostsFirst: undefined, - newPostsFirstHelp: undefined, - allowGiphy: 'Giphy toestaan', - allowGiphyHelp: - 'Gebruikers toestaan een Giphy afbeelding bij een retropunt te plaatsen', - allowGrouping: 'Groeperen toestaan', - allowGroupingHelp: 'Aanmaken van groepen van retropunten toestaan.', - allowReordering: 'Herordenen toestaan', - allowReorderingHelp: - 'Toestaan om retropunten mbv drag-en-drop te herordenen', - blurCards: undefined, - blurCardsHelp: undefined, - template: 'Template', - templateHelp: 'Gebruik een vooringestelde set kolommen', - numberOfColumns: 'Aantal kolommen', - numberOfColumnsHelp: 'Stel het aantal kolommen in', - makeDefaultTemplate: 'Stel in als mijn standaard template', - }, - PostBoard: { - customQuestion: 'Aangepast kolom', - notWellQuestion: 'Wat kan er beter?', - wellQuestion: 'Wat ging goed?', - ideasQuestion: 'Een geweldig idee om te delen?', - startQuestion: 'Start', - editButton: undefined, - stopQuestion: 'Stop', - continueQuestion: 'Blijven doen', - likedQuestion: 'Liked (Leuk)', - lackedQuestion: 'Lacked (Ontbrak)', - learnedQuestion: 'Learned (Geleerd)', - longedForQuestion: 'Longed for (Gewild)', - anchorQuestion: 'Anker', - boatQuestion: 'Boot', - islandQuestion: 'Eiland', - windQuestion: 'Wind', - rockQuestion: 'Steen', - disconnected: 'Je huidige sessie is verbroken', - reconnect: 'Opnieuw verbinden', - notLoggedIn: - 'Je bent niet ingelogd. Je kan de sessie bekijken als toeschouwer maar moet inloggen om deel te nemen.', - maxPostsReached: undefined, - iAmDone: undefined, - iAmNotDoneYet: undefined, - userIsReady: undefined, - }, - GameMenu: { - board: 'Bord', - summary: 'Samenvatting', - }, - Template: { - default: 'Standaard', - wellNotWell: 'Goed / Niet goed', - startStopContinue: 'Start / Stop / Blijven doen', - fourLs: `De 4 L'en`, - sailboat: 'Zeilboot', - }, - Clients: { - header: 'Deelnemers:', - joined: undefined, - left: undefined, - }, - Join: { - welcome: 'Welkom bij Retrospected', - standardTab: { - header: 'Starten', - text: 'Klik hieronder en begin je retrospective:', - button: 'Start een nieuwe sessie', - customizeButton: 'Aanpassen', - }, - optionsTab: { - header: 'Opties', - input: 'Naam', - button: 'Start een aangepaste sessie', - }, - previousTab: { - header: 'Vorige sessies', - rejoinButton: 'Opnieuw deelnemen', - }, - }, - AnonymousLogin: { - namePlaceholder: 'Laat weten wie je bent met je naam', - buttonLabel: 'Laten we beginnen', - header: 'Login', - anonymousAuthHeader: 'Aanmelden zonder account', - anonymousAuthDescription: - 'Hiermee maak je aan anonieme account aan. Hiermee kan geen sessies opslaan en terughalen.', - authenticatingWith: 'Authenticeer met', - or: 'of', - }, - SocialMediaLogin: { - header: 'Social Media authenticatie', - info: 'Dit gebruikt je social media account en slaat de sessies op onder je account. Er is geen wachtwoord nodig.', - }, - AuthCommon: { - emailField: undefined, - passwordField: undefined, - nameField: undefined, - passwordScoreWords: undefined, - }, - AccountLogin: { - header: undefined, - loginButton: undefined, - info: undefined, - registerLink: undefined, - forgotPasswordLink: undefined, - errorEmailPasswordIncorrect: undefined, - }, - Register: { - header: undefined, - info: undefined, - registerButton: undefined, - errorAlreadyRegistered: undefined, - errorGeneral: undefined, - messageSuccess: undefined, - errorInvalidEmail: undefined, - }, - ValidateAccount: { - success: undefined, - error: undefined, - loading: undefined, - }, - ResetPassword: { - // Reset Modal - doneMessage: undefined, - header: undefined, - resetButton: undefined, - info: undefined, - // Reset Page - success: undefined, - error: undefined, - loading: undefined, - resetInfo: undefined, - }, - SummaryBoard: { - noPosts: 'Er zijn geen retropunten om te tonen', - copyAsMarkdown: 'Kopieer de samenvatting als Markdown', - copyAsRichText: 'Kopieer de samenvatting als rich-text', - copySuccessful: - 'Je hebt de samenvatting succesvol naar het klembord gekopieerd', - }, - SessionName: { - defaultSessionName: 'Mijn Retrospective', - }, - Invite: { - inviteButton: 'Uitnodigen', - dialog: { - title: 'Nodig mensen uit voor jouw retrospective', - text: - 'Stuur de mensen die je wil uitnodigen voor jouw retrospective ' + - 'sessie de volgende url', - copyButton: 'Kopieer URL naar klembord', - }, - }, - Generic: { - ok: 'OK', - cancel: 'Annuleren', - }, - Actions: { - tooltip: 'Maak een actie op de achterkant van dit item', - label: 'Open het actiepaneel', - summaryTitle: 'Jouw acties', - title: 'Actie', - }, - DeleteSession: { - header: undefined, - firstLine: undefined, - secondLine: undefined, - yesImSure: undefined, - cancel: undefined, - }, - RevealCards: { - buttonLabel: undefined, - dialogTitle: undefined, - dialogContent: undefined, - confirmButton: undefined, - cancelButton: undefined, - }, - AccountPage: { - anonymousError: undefined, - details: { - header: undefined, - username: undefined, - email: undefined, - accountType: undefined, - }, - plan: { - header: undefined, - plan: undefined, - youAreOwner: undefined, - youAreMember: undefined, - }, - subscription: { - header: undefined, - manageButton: undefined, - membersEditor: { - title: undefined, - limitReached: undefined, - info: undefined, - }, - }, - trial: { - header: undefined, - yourTrialWillExpireIn: undefined, - subscribe: undefined, - }, - deleteAccount: { - title: undefined, - warning: undefined, - deleteData: undefined, - modal: { - confirm: { - title: undefined, - description: undefined, - confirmation: undefined, - cancellation: undefined, - }, - subheader: undefined, - deleteAccount: undefined, - recommended: undefined, - deleteSessions: { - main: undefined, - selected: undefined, - unselected: undefined, - }, - deletePosts: { - main: undefined, - selected: undefined, - unselected: undefined, - }, - deleteVotes: { - main: undefined, - selected: undefined, - unselected: undefined, - }, - deleteAccountButton: undefined, - cancelButton: undefined, - }, - }, - }, - SubscribePage: { - alertAlreadyPro: undefined, - alertAlreadySubscribed: undefined, - currency: { - title: undefined, - description: undefined, - warning: undefined, - }, - plan: { - title: undefined, - description: undefined, - }, - domain: { - title: undefined, - description: undefined, - invalidDomain: undefined, - }, - subscribe: { - title: undefined, - description: undefined, - cannotRegisterWithAnon: undefined, - checkout: undefined, - }, - }, - SubscribeModal: { - title: undefined, - header: undefined, - description: undefined, - features: { - encryptedSession: { - title: undefined, - description: undefined, - }, - privateSessions: { - title: undefined, - description: undefined, - }, - unlimitedPosts: { - title: undefined, - description: undefined, - }, - }, - subscribeButton: undefined, - payButton: undefined, - cancelButton: undefined, - startTrial: undefined, - }, - Products: { - team: undefined, - unlimited: undefined, - 'self-hosted': undefined, - users: undefined, - unlimited_seats: undefined, - month: undefined, - year: undefined, - wantToPayYearly: undefined, - }, - Encryption: { - createEncryptedSession: undefined, - sessionNotEncrypted: undefined, - sessionEncryptedHaveKeyTooltip: undefined, - sessionEncryptedNoKeyTooltip: undefined, - sessionEncryptedWrongKeyTooltip: undefined, - newEncryptedSessionWarningTitle: undefined, - newEncryptedSessionWarningContent: undefined, - sessionEncryptionError: undefined, - passwordModalTitle: undefined, - passwordModelIncorrect: undefined, - }, - Private: { - lockSuccessNotification: undefined, - unlockSuccessNotification: undefined, - lockButton: undefined, - unlockButton: undefined, - lockDescription: undefined, - cancelButton: undefined, - sessionLockedTitle: undefined, - sessionLockedDescription: undefined, - sessionNonProTitle: undefined, - sessionNonProDescription: undefined, - sessionIsPublic: undefined, - sessionIsPrivate: undefined, - sessionIsPrivateNoAccess: undefined, - }, - TrialPrompt: { - allowanceReachedTitle: undefined, - allowanceReachedDescription: undefined, - nearEndAllowanceTitle: undefined, - nearEndAllowanceDescription: undefined, - onTrialTitle: undefined, - remainingTrialSentence: undefined, - trialEndedTitle: undefined, - trialEndedSentence: undefined, - subscribeNow: undefined, - }, - Chat: { writeAMessage: undefined }, -} as Translation; diff --git a/frontend/src/translations/pl.ts b/frontend/src/translations/pl.ts deleted file mode 100644 index 88d50a56a..000000000 --- a/frontend/src/translations/pl.ts +++ /dev/null @@ -1,406 +0,0 @@ -import { Translation } from './types'; -export default { - Header: { - subtitle: 'Dobry sposób by ponarzekać zgodnie z duchem Agile', - logout: 'Wyloguj', - leave: 'Wyjdź', - summaryMode: 'Tryb Podsumowania', - account: undefined, - adminPanel: undefined, - }, - LanguagePicker: { - header: 'Wybierz język', - }, - Main: { - hint: 'Możesz zaprosić inne osoby do tej sesji wysyłając im URL', - }, - Home: { - welcome: undefined, - }, - PreviousGame: { - createdBy: undefined, - posts: undefined, - participants: undefined, - votes: undefined, - actions: undefined, - }, - Column: { - createGroupTooltip: undefined, - }, - Group: { - emptyGroupTitle: '', - emptyGroupContent: '', - }, - Post: { - openExtra: undefined, - closeExtra: undefined, - vote: 'głos', - votes: 'głosów', - deleteButton: 'Usuń', - setActionButton: undefined, - setGiphyButton: undefined, - noContent: '(Ten wpis nie ma zawartości)', - by: undefined, - upVote: undefined, - downVote: undefined, - voteRemainingMultiple: undefined, - voteRemainingOne: undefined, - voteRemainingNone: undefined, - toggleGiphyButton: undefined, - }, - Customize: { - title: undefined, - votingCategory: undefined, - votingCategorySub: undefined, - postCategory: undefined, - postCategorySub: undefined, - customTemplateCategory: undefined, - customTemplateCategorySub: undefined, - startButton: undefined, - editButton: undefined, - maxUpVotes: undefined, - maxUpVotesHelp: undefined, - maxDownVotes: undefined, - maxDownVotesHelp: undefined, - maxPosts: undefined, - maxPostsHelp: undefined, - allowSelfVoting: undefined, - allowSelfVotingHelp: undefined, - allowMultipleVotes: undefined, - allowMultipleVotesHelp: undefined, - allowActions: undefined, - allowActionsHelp: undefined, - allowAuthorVisible: undefined, - allowAuthorVisibleHelp: undefined, - newPostsFirst: undefined, - newPostsFirstHelp: undefined, - allowGiphy: undefined, - allowGiphyHelp: undefined, - allowGrouping: undefined, - allowGroupingHelp: undefined, - allowReordering: undefined, - allowReorderingHelp: undefined, - blurCards: undefined, - blurCardsHelp: undefined, - template: undefined, - templateHelp: undefined, - numberOfColumns: undefined, - numberOfColumnsHelp: undefined, - makeDefaultTemplate: undefined, - }, - PostBoard: { - customQuestion: undefined, - notWellQuestion: 'Co można poprawić?', - wellQuestion: 'Co poszło dobrze?', - ideasQuestion: 'Wspaniały pomysł którym chcesz się podzielić?', - startQuestion: undefined, - editButton: undefined, - stopQuestion: undefined, - continueQuestion: undefined, - likedQuestion: undefined, - lackedQuestion: undefined, - learnedQuestion: undefined, - longedForQuestion: undefined, - anchorQuestion: undefined, - boatQuestion: undefined, - islandQuestion: undefined, - windQuestion: undefined, - rockQuestion: undefined, - disconnected: undefined, - reconnect: undefined, - notLoggedIn: undefined, - error: undefined, - maxPostsReached: undefined, - iAmDone: undefined, - iAmNotDoneYet: undefined, - userIsReady: undefined, - }, - GameMenu: { - board: undefined, - summary: undefined, - }, - Template: { - default: undefined, - wellNotWell: undefined, - startStopContinue: undefined, - fourLs: undefined, - sailboat: undefined, - }, - Clients: { - header: 'Są dziś z nami:', - joined: undefined, - left: undefined, - }, - Join: { - welcome: 'Witaj w Retrospected', - standardTab: { - header: 'Stwórz', - text: 'Kliknij poniżej i zacznij retrospektywę:', - button: 'Stwórz nową sesję', - customizeButton: undefined, - }, - optionsTab: { - header: 'Zaawansowane', - input: 'Imię', - button: 'Stwórz custom session', - }, - previousTab: { - header: 'Poprzednie', - rejoinButton: 'Dołącz ponownie', - }, - }, - AnonymousLogin: { - namePlaceholder: 'Kim dokładnie jesteś? Wprowadź tu swoje imię', - buttonLabel: 'Zacznijmy', - header: 'Login', - anonymousAuthHeader: undefined, - anonymousAuthDescription: undefined, - authenticatingWith: undefined, - or: undefined, - }, - SocialMediaLogin: { - header: undefined, - info: undefined, - }, - AuthCommon: { - emailField: undefined, - passwordField: undefined, - nameField: undefined, - passwordScoreWords: undefined, - }, - AccountLogin: { - header: undefined, - loginButton: undefined, - info: undefined, - registerLink: undefined, - forgotPasswordLink: undefined, - errorEmailPasswordIncorrect: undefined, - }, - Register: { - header: undefined, - info: undefined, - registerButton: undefined, - errorAlreadyRegistered: undefined, - errorGeneral: undefined, - messageSuccess: undefined, - errorInvalidEmail: undefined, - }, - ValidateAccount: { - success: undefined, - error: undefined, - loading: undefined, - }, - ResetPassword: { - // Reset Modal - doneMessage: undefined, - header: undefined, - resetButton: undefined, - info: undefined, - // Reset Page - success: undefined, - error: undefined, - loading: undefined, - resetInfo: undefined, - }, - SummaryBoard: { - noPosts: 'Nie ma wpisów do wyświetlenia', - copyAsMarkdown: undefined, - copyAsRichText: undefined, - copySuccessful: undefined, - }, - SessionName: { - defaultSessionName: 'Moja Retrospektywa', - }, - Invite: { - inviteButton: 'Zaproś', - dialog: { - title: 'Zaproś ludzi do swojej retrospektywy', - text: - 'By zaprosić ludzi do swojej retrospektywy, po prostu wyślij im ' + - 'następujący URL', - copyButton: 'Skopiuj URL do Schowka', - }, - }, - Generic: { - ok: 'OK', - cancel: 'Anuluj', - }, - Actions: { - tooltip: 'Utwórz akcję z tyłu tego elementu', - label: 'Otwórz panel Akcja', - summaryTitle: 'Twoje działania', - title: 'Akcja', - }, - DeleteSession: { - header: undefined, - firstLine: undefined, - secondLine: undefined, - yesImSure: undefined, - cancel: undefined, - }, - RevealCards: { - buttonLabel: undefined, - dialogTitle: undefined, - dialogContent: undefined, - confirmButton: undefined, - cancelButton: undefined, - }, - AccountPage: { - anonymousError: undefined, - details: { - header: undefined, - username: undefined, - email: undefined, - accountType: undefined, - }, - plan: { - header: undefined, - plan: undefined, - youAreOwner: undefined, - youAreMember: undefined, - }, - subscription: { - header: undefined, - manageButton: undefined, - membersEditor: { - title: undefined, - limitReached: undefined, - info: undefined, - }, - }, - trial: { - header: undefined, - yourTrialWillExpireIn: undefined, - subscribe: undefined, - }, - deleteAccount: { - title: undefined, - warning: undefined, - deleteData: undefined, - modal: { - confirm: { - title: undefined, - description: undefined, - confirmation: undefined, - cancellation: undefined, - }, - subheader: undefined, - deleteAccount: undefined, - recommended: undefined, - deleteSessions: { - main: undefined, - selected: undefined, - unselected: undefined, - }, - deletePosts: { - main: undefined, - selected: undefined, - unselected: undefined, - }, - deleteVotes: { - main: undefined, - selected: undefined, - unselected: undefined, - }, - deleteAccountButton: undefined, - cancelButton: undefined, - }, - }, - }, - SubscribePage: { - alertAlreadyPro: undefined, - alertAlreadySubscribed: undefined, - currency: { - title: undefined, - description: undefined, - warning: undefined, - }, - plan: { - title: undefined, - description: undefined, - }, - domain: { - title: undefined, - description: undefined, - invalidDomain: undefined, - }, - subscribe: { - title: undefined, - description: undefined, - cannotRegisterWithAnon: undefined, - checkout: undefined, - }, - }, - SubscribeModal: { - title: undefined, - header: undefined, - description: undefined, - features: { - encryptedSession: { - title: undefined, - description: undefined, - }, - privateSessions: { - title: undefined, - description: undefined, - }, - unlimitedPosts: { - title: undefined, - description: undefined, - }, - }, - subscribeButton: undefined, - payButton: undefined, - cancelButton: undefined, - startTrial: undefined, - }, - Products: { - team: undefined, - unlimited: undefined, - 'self-hosted': undefined, - users: undefined, - unlimited_seats: undefined, - month: undefined, - year: undefined, - wantToPayYearly: undefined, - }, - Encryption: { - createEncryptedSession: undefined, - sessionNotEncrypted: undefined, - sessionEncryptedHaveKeyTooltip: undefined, - sessionEncryptedNoKeyTooltip: undefined, - sessionEncryptedWrongKeyTooltip: undefined, - newEncryptedSessionWarningTitle: undefined, - newEncryptedSessionWarningContent: undefined, - sessionEncryptionError: undefined, - passwordModalTitle: undefined, - passwordModelIncorrect: undefined, - }, - Private: { - lockSuccessNotification: undefined, - unlockSuccessNotification: undefined, - lockButton: undefined, - unlockButton: undefined, - lockDescription: undefined, - cancelButton: undefined, - sessionLockedTitle: undefined, - sessionLockedDescription: undefined, - sessionNonProTitle: undefined, - sessionNonProDescription: undefined, - sessionIsPublic: undefined, - sessionIsPrivate: undefined, - sessionIsPrivateNoAccess: undefined, - }, - TrialPrompt: { - allowanceReachedTitle: undefined, - allowanceReachedDescription: undefined, - nearEndAllowanceTitle: undefined, - nearEndAllowanceDescription: undefined, - onTrialTitle: undefined, - remainingTrialSentence: undefined, - trialEndedTitle: undefined, - trialEndedSentence: undefined, - subscribeNow: undefined, - }, - Chat: { writeAMessage: undefined }, -} as Translation; diff --git a/frontend/src/translations/pt-br.ts b/frontend/src/translations/pt-br.ts deleted file mode 100644 index 8decda500..000000000 --- a/frontend/src/translations/pt-br.ts +++ /dev/null @@ -1,406 +0,0 @@ -import { Translation } from './types'; -export default { - Header: { - subtitle: 'Uma ótima maneira de reclamar se divertindo', - logout: 'Logout', - leave: 'Sair', - summaryMode: 'Modo Sumário', - account: undefined, - adminPanel: undefined, - }, - LanguagePicker: { - header: 'Escolha uma língua', - }, - Main: { - hint: 'Você pode convidar outras pessoas para esta seção compartilhando a URL', - }, - Home: { - welcome: undefined, - }, - PreviousGame: { - createdBy: undefined, - posts: undefined, - participants: undefined, - votes: undefined, - actions: undefined, - }, - Column: { - createGroupTooltip: undefined, - }, - Group: { - emptyGroupTitle: '', - emptyGroupContent: '', - }, - Post: { - openExtra: undefined, - closeExtra: undefined, - vote: 'vote', - votes: 'votos', - deleteButton: 'Remover', - setActionButton: undefined, - setGiphyButton: undefined, - noContent: '(This post has no content)', - by: undefined, - upVote: undefined, - downVote: undefined, - voteRemainingMultiple: undefined, - voteRemainingOne: undefined, - voteRemainingNone: undefined, - toggleGiphyButton: undefined, - }, - Customize: { - title: undefined, - votingCategory: undefined, - votingCategorySub: undefined, - postCategory: undefined, - postCategorySub: undefined, - customTemplateCategory: undefined, - customTemplateCategorySub: undefined, - startButton: undefined, - editButton: undefined, - maxUpVotes: undefined, - maxUpVotesHelp: undefined, - maxDownVotes: undefined, - maxDownVotesHelp: undefined, - maxPosts: undefined, - maxPostsHelp: undefined, - allowSelfVoting: undefined, - allowSelfVotingHelp: undefined, - allowMultipleVotes: undefined, - allowMultipleVotesHelp: undefined, - allowActions: undefined, - allowActionsHelp: undefined, - allowAuthorVisible: undefined, - allowAuthorVisibleHelp: undefined, - newPostsFirst: undefined, - newPostsFirstHelp: undefined, - allowGiphy: undefined, - allowGiphyHelp: undefined, - allowGrouping: undefined, - allowGroupingHelp: undefined, - allowReordering: undefined, - allowReorderingHelp: undefined, - blurCards: undefined, - blurCardsHelp: undefined, - template: undefined, - templateHelp: undefined, - numberOfColumns: undefined, - numberOfColumnsHelp: undefined, - makeDefaultTemplate: undefined, - }, - PostBoard: { - customQuestion: undefined, - notWellQuestion: 'O que poderia ser melhorado?', - wellQuestion: 'O que deu certo?', - ideasQuestion: 'Compartilhar uma ideia brilhante?', - startQuestion: undefined, - editButton: undefined, - stopQuestion: undefined, - continueQuestion: undefined, - likedQuestion: undefined, - lackedQuestion: undefined, - learnedQuestion: undefined, - longedForQuestion: undefined, - anchorQuestion: undefined, - boatQuestion: undefined, - islandQuestion: undefined, - windQuestion: undefined, - rockQuestion: undefined, - disconnected: undefined, - reconnect: undefined, - notLoggedIn: undefined, - error: undefined, - maxPostsReached: undefined, - iAmDone: undefined, - iAmNotDoneYet: undefined, - userIsReady: undefined, - }, - GameMenu: { - board: undefined, - summary: undefined, - }, - Template: { - default: undefined, - wellNotWell: undefined, - startStopContinue: undefined, - fourLs: undefined, - sailboat: undefined, - }, - Clients: { - header: 'Participando conosco agora:', - joined: undefined, - left: undefined, - }, - Join: { - welcome: 'Bem-vindo ao Retrospected', - standardTab: { - header: 'Crie uma seção', - text: 'Clique abaixo e inicie a restropectiva:', - button: 'Crie uma nova seção', - customizeButton: undefined, - }, - optionsTab: { - header: 'Avançado', - input: 'Insira um nome para sua seção', - button: 'Crie uma seção customizada', - }, - previousTab: { - header: 'Previous sessions', - rejoinButton: 'Rejoin', - }, - }, - AnonymousLogin: { - namePlaceholder: 'Quem é você? Insira seu nome aqui', - buttonLabel: 'Vamos começar', - header: 'Login', - anonymousAuthHeader: undefined, - anonymousAuthDescription: undefined, - authenticatingWith: undefined, - or: undefined, - }, - SocialMediaLogin: { - header: undefined, - info: undefined, - }, - AuthCommon: { - emailField: undefined, - passwordField: undefined, - nameField: undefined, - passwordScoreWords: undefined, - }, - AccountLogin: { - header: undefined, - loginButton: undefined, - info: undefined, - registerLink: undefined, - forgotPasswordLink: undefined, - errorEmailPasswordIncorrect: undefined, - }, - Register: { - header: undefined, - info: undefined, - registerButton: undefined, - errorAlreadyRegistered: undefined, - errorGeneral: undefined, - messageSuccess: undefined, - errorInvalidEmail: undefined, - }, - ValidateAccount: { - success: undefined, - error: undefined, - loading: undefined, - }, - ResetPassword: { - // Reset Modal - doneMessage: undefined, - header: undefined, - resetButton: undefined, - info: undefined, - // Reset Page - success: undefined, - error: undefined, - loading: undefined, - resetInfo: undefined, - }, - SummaryBoard: { - noPosts: 'There are no posts to display', - copyAsMarkdown: undefined, - copyAsRichText: undefined, - copySuccessful: undefined, - }, - SessionName: { - defaultSessionName: 'My Retrospective', - }, - Invite: { - inviteButton: 'Invite', - dialog: { - title: 'Invite people to your retrospective', - text: - 'To invite people to your retrospected session, simply send them ' + - 'the following URL', - copyButton: 'Copy URL to Clipboard', - }, - }, - Generic: { - ok: 'OK', - cancel: 'Cancelar', - }, - Actions: { - tooltip: 'Crie uma ação no verso deste item', - label: 'Abra o painel de ação', - summaryTitle: 'Suas ações', - title: 'Açao', - }, - DeleteSession: { - header: undefined, - firstLine: undefined, - secondLine: undefined, - yesImSure: undefined, - cancel: undefined, - }, - RevealCards: { - buttonLabel: undefined, - dialogTitle: undefined, - dialogContent: undefined, - confirmButton: undefined, - cancelButton: undefined, - }, - AccountPage: { - anonymousError: undefined, - details: { - header: undefined, - username: undefined, - email: undefined, - accountType: undefined, - }, - plan: { - header: undefined, - plan: undefined, - youAreOwner: undefined, - youAreMember: undefined, - }, - subscription: { - header: undefined, - manageButton: undefined, - membersEditor: { - title: undefined, - limitReached: undefined, - info: undefined, - }, - }, - trial: { - header: undefined, - yourTrialWillExpireIn: undefined, - subscribe: undefined, - }, - deleteAccount: { - title: undefined, - warning: undefined, - deleteData: undefined, - modal: { - confirm: { - title: undefined, - description: undefined, - confirmation: undefined, - cancellation: undefined, - }, - subheader: undefined, - deleteAccount: undefined, - recommended: undefined, - deleteSessions: { - main: undefined, - selected: undefined, - unselected: undefined, - }, - deletePosts: { - main: undefined, - selected: undefined, - unselected: undefined, - }, - deleteVotes: { - main: undefined, - selected: undefined, - unselected: undefined, - }, - deleteAccountButton: undefined, - cancelButton: undefined, - }, - }, - }, - SubscribePage: { - alertAlreadyPro: undefined, - alertAlreadySubscribed: undefined, - currency: { - title: undefined, - description: undefined, - warning: undefined, - }, - plan: { - title: undefined, - description: undefined, - }, - domain: { - title: undefined, - description: undefined, - invalidDomain: undefined, - }, - subscribe: { - title: undefined, - description: undefined, - cannotRegisterWithAnon: undefined, - checkout: undefined, - }, - }, - SubscribeModal: { - title: undefined, - header: undefined, - description: undefined, - features: { - encryptedSession: { - title: undefined, - description: undefined, - }, - privateSessions: { - title: undefined, - description: undefined, - }, - unlimitedPosts: { - title: undefined, - description: undefined, - }, - }, - subscribeButton: undefined, - payButton: undefined, - cancelButton: undefined, - startTrial: undefined, - }, - Products: { - team: undefined, - unlimited: undefined, - 'self-hosted': undefined, - users: undefined, - unlimited_seats: undefined, - month: undefined, - year: undefined, - wantToPayYearly: undefined, - }, - Encryption: { - createEncryptedSession: undefined, - sessionNotEncrypted: undefined, - sessionEncryptedHaveKeyTooltip: undefined, - sessionEncryptedNoKeyTooltip: undefined, - sessionEncryptedWrongKeyTooltip: undefined, - newEncryptedSessionWarningTitle: undefined, - newEncryptedSessionWarningContent: undefined, - sessionEncryptionError: undefined, - passwordModalTitle: undefined, - passwordModelIncorrect: undefined, - }, - Private: { - lockSuccessNotification: undefined, - unlockSuccessNotification: undefined, - lockButton: undefined, - unlockButton: undefined, - lockDescription: undefined, - cancelButton: undefined, - sessionLockedTitle: undefined, - sessionLockedDescription: undefined, - sessionNonProTitle: undefined, - sessionNonProDescription: undefined, - sessionIsPublic: undefined, - sessionIsPrivate: undefined, - sessionIsPrivateNoAccess: undefined, - }, - TrialPrompt: { - allowanceReachedTitle: undefined, - allowanceReachedDescription: undefined, - nearEndAllowanceTitle: undefined, - nearEndAllowanceDescription: undefined, - onTrialTitle: undefined, - remainingTrialSentence: undefined, - trialEndedTitle: undefined, - trialEndedSentence: undefined, - subscribeNow: undefined, - }, - Chat: { writeAMessage: undefined }, -} as Translation; diff --git a/frontend/src/translations/react-i18next.d.ts b/frontend/src/translations/react-i18next.d.ts new file mode 100644 index 000000000..845edd35b --- /dev/null +++ b/frontend/src/translations/react-i18next.d.ts @@ -0,0 +1,11 @@ +import 'react-i18next'; +import ns1 from './locales/en-GB.json'; + +declare module 'react-i18next' { + interface CustomTypeOptions { + defaultNS: 'ns1'; + resources: { + ns1: typeof ns1; + }; + } +} diff --git a/frontend/src/translations/readme.md b/frontend/src/translations/readme.md new file mode 100644 index 000000000..86b28c8da --- /dev/null +++ b/frontend/src/translations/readme.md @@ -0,0 +1,23 @@ +# How to deal with translations + +## Install the Crowdin CLI + +https://support.crowdin.com/cli-tool/ + +- `brew tap crowdin/crowdin` +- `brew install crowdin@3` + +## Set authentication + +On the home directory (`~/`): + +- `crowdin init` + +## Download and upload translations + +- `crowdin download` +- `crowdin push translations` + +## Push a new source + +- `crowdin push sources` \ No newline at end of file diff --git a/frontend/src/translations/ru.ts b/frontend/src/translations/ru.ts deleted file mode 100644 index c55ddd02c..000000000 --- a/frontend/src/translations/ru.ts +++ /dev/null @@ -1,404 +0,0 @@ -import { Translation } from './types'; -export default { - Header: { - subtitle: 'Отличный способ выговориться прилично', - leave: 'Выйти', - logout: 'Выйти с учётной записи', - summaryMode: 'Показать итоги', - account: undefined, - adminPanel: undefined, - }, - LanguagePicker: { - header: 'Выбрать язык', - }, - Main: { - hint: 'Просто отправьте ссылку, чтобы пригласить на эту рестроспективу', - }, - Home: { - welcome: undefined, - }, - PreviousGame: { - createdBy: undefined, - posts: undefined, - participants: undefined, - votes: undefined, - actions: undefined, - }, - Column: { - createGroupTooltip: undefined, - }, - Group: { - emptyGroupTitle: '', - emptyGroupContent: '', - }, - Post: { - openExtra: undefined, - closeExtra: undefined, - vote: 'голос', - votes: 'голоса', - deleteButton: 'Удалить', - setActionButton: undefined, - setGiphyButton: undefined, - noContent: '(пусто)', - by: undefined, - upVote: undefined, - downVote: undefined, - voteRemainingMultiple: undefined, - voteRemainingOne: undefined, - voteRemainingNone: undefined, - toggleGiphyButton: undefined, - }, - Customize: { - title: undefined, - votingCategory: undefined, - votingCategorySub: undefined, - postCategory: undefined, - postCategorySub: undefined, - customTemplateCategory: undefined, - customTemplateCategorySub: undefined, - startButton: undefined, - editButton: undefined, - maxUpVotes: undefined, - maxUpVotesHelp: undefined, - maxDownVotes: undefined, - maxDownVotesHelp: undefined, - maxPosts: undefined, - maxPostsHelp: undefined, - allowSelfVoting: undefined, - allowSelfVotingHelp: undefined, - allowMultipleVotes: undefined, - allowMultipleVotesHelp: undefined, - allowActions: undefined, - allowActionsHelp: undefined, - allowAuthorVisible: undefined, - allowAuthorVisibleHelp: undefined, - newPostsFirst: undefined, - newPostsFirstHelp: undefined, - allowGiphy: undefined, - allowGiphyHelp: undefined, - allowGrouping: undefined, - allowGroupingHelp: undefined, - allowReordering: undefined, - allowReorderingHelp: undefined, - blurCards: undefined, - blurCardsHelp: undefined, - template: undefined, - templateHelp: undefined, - numberOfColumns: undefined, - numberOfColumnsHelp: undefined, - makeDefaultTemplate: undefined, - }, - PostBoard: { - customQuestion: undefined, - notWellQuestion: 'Что можно улучшить?', - wellQuestion: 'Что было хорошего?', - ideasQuestion: 'Другие хорошие идеи?', - startQuestion: undefined, - editButton: undefined, - stopQuestion: undefined, - continueQuestion: undefined, - likedQuestion: undefined, - lackedQuestion: undefined, - learnedQuestion: undefined, - longedForQuestion: undefined, - anchorQuestion: undefined, - boatQuestion: undefined, - islandQuestion: undefined, - windQuestion: undefined, - rockQuestion: undefined, - disconnected: undefined, - reconnect: undefined, - notLoggedIn: undefined, - error: undefined, - maxPostsReached: undefined, - iAmDone: undefined, - iAmNotDoneYet: undefined, - userIsReady: undefined, - }, - GameMenu: { - board: 'Записи', - summary: 'Cводка', - }, - Template: { - default: undefined, - wellNotWell: undefined, - startStopContinue: undefined, - fourLs: undefined, - sailboat: undefined, - }, - Clients: { - header: 'Участники:', - joined: undefined, - left: undefined, - }, - Join: { - welcome: 'Добро пожаловать в Retrospected', - standardTab: { - header: 'Новая ретроспектива', - text: 'Нажмите, чтобы начать:', - button: 'Создать новую ретроспективу', - customizeButton: 'Настроить', - }, - optionsTab: { - header: 'Дополнительно', - input: 'Введите название ретроспективы', - button: 'Создать ретроспективу', - }, - previousTab: { - header: 'История', - rejoinButton: 'Войти', - }, - }, - AnonymousLogin: { - namePlaceholder: 'Как вас зовут? Введите имя', - buttonLabel: 'Начать', - header: 'Логин', - anonymousAuthHeader: undefined, - anonymousAuthDescription: undefined, - authenticatingWith: undefined, - or: undefined, - }, - SocialMediaLogin: { - header: undefined, - info: undefined, - }, - AuthCommon: { - emailField: undefined, - passwordField: undefined, - nameField: undefined, - passwordScoreWords: undefined, - }, - AccountLogin: { - header: undefined, - loginButton: undefined, - info: undefined, - registerLink: undefined, - forgotPasswordLink: undefined, - errorEmailPasswordIncorrect: undefined, - }, - Register: { - header: undefined, - info: undefined, - registerButton: undefined, - errorAlreadyRegistered: undefined, - errorGeneral: undefined, - messageSuccess: undefined, - errorInvalidEmail: undefined, - }, - ValidateAccount: { - success: undefined, - error: undefined, - loading: undefined, - }, - ResetPassword: { - // Reset Modal - doneMessage: undefined, - header: undefined, - resetButton: undefined, - info: undefined, - // Reset Page - success: undefined, - error: undefined, - loading: undefined, - resetInfo: undefined, - }, - SummaryBoard: { - noPosts: 'Здесь пока пусто', - copyAsMarkdown: 'Скопировать как Markdown', - copyAsRichText: 'Скопировать как RTF', - copySuccessful: 'Копирование завершено', - }, - SessionName: { - defaultSessionName: 'Наша ретроспектива', - }, - Invite: { - inviteButton: 'Пригласить', - dialog: { - title: 'Пригласить на ретроспективу', - text: 'Чтобы пригласить на ретроспективу, просто отправьте ссылку', - copyButton: 'Скопировать ссылку', - }, - }, - Generic: { - ok: 'OK', - cancel: 'отменить', - }, - Actions: { - tooltip: 'Создать действие на задней части этого элемента', - label: 'Откройте панель действий', - summaryTitle: 'Ваши действия', - title: 'действие', - }, - DeleteSession: { - header: undefined, - firstLine: undefined, - secondLine: undefined, - yesImSure: undefined, - cancel: undefined, - }, - RevealCards: { - buttonLabel: undefined, - dialogTitle: undefined, - dialogContent: undefined, - confirmButton: undefined, - cancelButton: undefined, - }, - AccountPage: { - anonymousError: undefined, - details: { - header: undefined, - username: undefined, - email: undefined, - accountType: undefined, - }, - plan: { - header: undefined, - plan: undefined, - youAreOwner: undefined, - youAreMember: undefined, - }, - subscription: { - header: undefined, - manageButton: undefined, - membersEditor: { - title: undefined, - limitReached: undefined, - info: undefined, - }, - }, - trial: { - header: undefined, - yourTrialWillExpireIn: undefined, - subscribe: undefined, - }, - deleteAccount: { - title: undefined, - warning: undefined, - deleteData: undefined, - modal: { - confirm: { - title: undefined, - description: undefined, - confirmation: undefined, - cancellation: undefined, - }, - subheader: undefined, - deleteAccount: undefined, - recommended: undefined, - deleteSessions: { - main: undefined, - selected: undefined, - unselected: undefined, - }, - deletePosts: { - main: undefined, - selected: undefined, - unselected: undefined, - }, - deleteVotes: { - main: undefined, - selected: undefined, - unselected: undefined, - }, - deleteAccountButton: undefined, - cancelButton: undefined, - }, - }, - }, - SubscribePage: { - alertAlreadyPro: undefined, - alertAlreadySubscribed: undefined, - currency: { - title: undefined, - description: undefined, - warning: undefined, - }, - plan: { - title: undefined, - description: undefined, - }, - domain: { - title: undefined, - description: undefined, - invalidDomain: undefined, - }, - subscribe: { - title: undefined, - description: undefined, - cannotRegisterWithAnon: undefined, - checkout: undefined, - }, - }, - SubscribeModal: { - title: undefined, - header: undefined, - description: undefined, - features: { - encryptedSession: { - title: undefined, - description: undefined, - }, - privateSessions: { - title: undefined, - description: undefined, - }, - unlimitedPosts: { - title: undefined, - description: undefined, - }, - }, - subscribeButton: undefined, - payButton: undefined, - cancelButton: undefined, - startTrial: undefined, - }, - Products: { - team: undefined, - unlimited: undefined, - 'self-hosted': undefined, - users: undefined, - unlimited_seats: undefined, - month: undefined, - year: undefined, - wantToPayYearly: undefined, - }, - Encryption: { - createEncryptedSession: undefined, - sessionNotEncrypted: undefined, - sessionEncryptedHaveKeyTooltip: undefined, - sessionEncryptedNoKeyTooltip: undefined, - sessionEncryptedWrongKeyTooltip: undefined, - newEncryptedSessionWarningTitle: undefined, - newEncryptedSessionWarningContent: undefined, - sessionEncryptionError: undefined, - passwordModalTitle: undefined, - passwordModelIncorrect: undefined, - }, - Private: { - lockSuccessNotification: undefined, - unlockSuccessNotification: undefined, - lockButton: undefined, - unlockButton: undefined, - lockDescription: undefined, - cancelButton: undefined, - sessionLockedTitle: undefined, - sessionLockedDescription: undefined, - sessionNonProTitle: undefined, - sessionNonProDescription: undefined, - sessionIsPublic: undefined, - sessionIsPrivate: undefined, - sessionIsPrivateNoAccess: undefined, - }, - TrialPrompt: { - allowanceReachedTitle: undefined, - allowanceReachedDescription: undefined, - nearEndAllowanceTitle: undefined, - nearEndAllowanceDescription: undefined, - onTrialTitle: undefined, - remainingTrialSentence: undefined, - trialEndedTitle: undefined, - trialEndedSentence: undefined, - subscribeNow: undefined, - }, - Chat: { writeAMessage: undefined }, -} as Translation; diff --git a/frontend/src/translations/types.ts b/frontend/src/translations/types.ts deleted file mode 100644 index 80022a891..000000000 --- a/frontend/src/translations/types.ts +++ /dev/null @@ -1,408 +0,0 @@ -import { WsErrorType } from 'common'; - -export type PluralWord = (numberOfItems: number) => string; - -export interface Translation { - Header: { - subtitle?: string; - logout?: string; - leave?: string; - summaryMode?: string; - account?: string; - adminPanel?: string; - }; - LanguagePicker: { - header?: string; - }; - Main: { - hint?: string; - }; - Home: { - welcome?: (userName: string) => string; - }; - PreviousGame: { - createdBy?: string; - posts?: PluralWord; - participants?: PluralWord; - votes?: PluralWord; - actions?: PluralWord; - }; - Column: { - createGroupTooltip?: string; - }; - Group: { - emptyGroupTitle?: string; - emptyGroupContent?: string; - }; - Post: { - openExtra?: string; - closeExtra?: string; - vote?: string; - votes?: string; - deleteButton?: string; - setActionButton?: string; - setGiphyButton?: string; - noContent?: string; - by?: string; - upVote?: string; - downVote?: string; - voteRemainingMultiple?: (count: number, type: string) => string; - voteRemainingOne?: (type: string) => string; - voteRemainingNone?: (type: string) => string; - toggleGiphyButton?: string; - }; - Customize: { - title?: string; - votingCategory?: string; - votingCategorySub?: string; - postCategory?: string; - postCategorySub?: string; - customTemplateCategory?: string; - customTemplateCategorySub?: string; - startButton?: string; - editButton?: string; - maxUpVotes?: string; - maxUpVotesHelp?: string; - maxPosts?: string; - maxPostsHelp?: string; - maxDownVotes?: string; - maxDownVotesHelp?: string; - allowSelfVoting?: string; - allowSelfVotingHelp?: string; - allowMultipleVotes?: string; - allowMultipleVotesHelp?: string; - allowActions?: string; - allowActionsHelp?: string; - allowAuthorVisible?: string; - allowAuthorVisibleHelp?: string; - newPostsFirst?: string; - newPostsFirstHelp?: string; - allowGiphy?: string; - allowGiphyHelp?: string; - allowGrouping?: string; - allowGroupingHelp?: string; - allowReordering?: string; - allowReorderingHelp?: string; - blurCards?: string; - blurCardsHelp?: string; - template?: string; - templateHelp?: string; - numberOfColumns?: string; - numberOfColumnsHelp?: string; - makeDefaultTemplate?: string; - }; - PostBoard: { - customQuestion?: string; - notWellQuestion?: string; - wellQuestion?: string; - ideasQuestion?: string; - startQuestion?: string; - stopQuestion?: string; - continueQuestion?: string; - likedQuestion?: string; - lackedQuestion?: string; - learnedQuestion?: string; - longedForQuestion?: string; - anchorQuestion?: string; - boatQuestion?: string; - islandQuestion?: string; - windQuestion?: string; - rockQuestion?: string; - disconnected?: string; - reconnect?: string; - notLoggedIn?: string; - error?: (error: WsErrorType) => string; - maxPostsReached?: string; - iAmDone?: string; - iAmNotDoneYet?: string; - userIsReady?: (userName: string) => string; - }; - GameMenu: { - board?: string; - summary?: string; - }; - Template: { - default?: string; - wellNotWell?: string; - startStopContinue?: string; - fourLs?: string; - sailboat?: string; - }; - Clients: { - header?: string; - joined?: (users: string) => string; - left?: (users: string) => string; - }; - Join: { - welcome?: string; - standardTab: { - header?: string; - text?: string; - button?: string; - customizeButton?: string; - }; - optionsTab: { - header?: string; - input?: string; - button?: string; - }; - previousTab: { - header?: string; - rejoinButton?: string; - }; - }; - AnonymousLogin: { - namePlaceholder?: string; - buttonLabel?: string; - header?: string; - anonymousAuthHeader?: string; - anonymousAuthDescription?: string; - authenticatingWith?: string; - or?: string; - }; - SocialMediaLogin: { - header?: string; - info?: string; - }; - AuthCommon: { - emailField?: string; - passwordField?: string; - nameField?: string; - passwordScoreWords?: string[]; - }; - AccountLogin: { - header?: string; - loginButton?: string; - info?: string; - registerLink?: string; - forgotPasswordLink?: string; - errorEmailPasswordIncorrect?: string; - }; - Register: { - header?: string; - info?: string; - registerButton?: string; - errorAlreadyRegistered?: string; - errorGeneral?: string; - messageSuccess?: string; - errorInvalidEmail?: string; - }; - ValidateAccount: { - success?: string; - error?: string; - loading?: string; - }; - ResetPassword: { - // Reset Modal - doneMessage?: string; - header?: string; - resetButton?: string; - info?: string; - // Reset Page - success?: string; - error?: string; - loading?: string; - resetInfo?: string; - }; - SummaryBoard: { - noPosts?: string; - copyAsMarkdown?: string; - copyAsRichText?: string; - copySuccessful?: string; - }; - SessionName: { - defaultSessionName?: string; - }; - Invite: { - inviteButton?: string; - dialog: { - title?: string; - text?: string; - copyButton?: string; - }; - }; - Generic: { - ok?: string; - cancel?: string; - }; - Actions: { - label?: string; - tooltip?: string; - title?: string; - summaryTitle?: string; - }; - DeleteSession: { - header?: (sessionName: string) => string; - firstLine?: string; - secondLine?: string; - yesImSure?: string; - cancel?: string; - }; - RevealCards: { - buttonLabel?: string; - dialogTitle?: string; - dialogContent?: string; - confirmButton?: string; - cancelButton?: string; - }; - AccountPage: { - anonymousError?: string; - details: { - header?: string; - username?: string; - email?: string; - accountType?: string; - }; - plan: { - header?: string; - plan?: string; - youAreOwner?: string; - youAreMember?: string; - }; - subscription: { - header?: string; - manageButton?: string; - membersEditor: { - title?: string; - limitReached?: (limit: number) => string; - info?: (limit: number) => string; - }; - }; - trial: { - header?: string; - yourTrialWillExpireIn?: (date: string) => string; - subscribe?: string; - }; - deleteAccount: { - title?: string; - warning?: string; - deleteData?: string; - modal: { - confirm: { - title?: string; - description?: string; - confirmation?: string; - cancellation?: string; - }; - subheader?: string; - deleteAccount?: string; - recommended?: string; - deleteSessions: { - main?: string; - selected?: string; - unselected?: string; - }; - deletePosts: { - main?: string; - selected?: string; - unselected?: string; - }; - deleteVotes: { - main?: string; - selected?: string; - unselected?: string; - }; - deleteAccountButton?: string; - cancelButton?: string; - }; - }; - }; - SubscribePage: { - alertAlreadyPro?: string; - alertAlreadySubscribed?: string; - currency: { - title?: string; - description?: string; - warning?: (currency: string) => string; - }; - plan: { - title?: string; - description?: string; - }; - domain: { - title?: string; - description?: string; - invalidDomain?: string; - }; - subscribe: { - title?: string; - description?: string; - cannotRegisterWithAnon?: string; - checkout?: string; - }; - }; - SubscribeModal: { - title?: string; - header?: string; - description?: string; - features: { - encryptedSession: { - title?: string; - description?: string; - }; - privateSessions: { - title?: string; - description?: string; - }; - unlimitedPosts: { - title?: string; - description?: string; - }; - }; - subscribeButton?: string; - payButton?: string; - cancelButton?: string; - startTrial?: string; - }; - Products: { - team?: string; - unlimited?: string; - 'self-hosted'?: string; - users?: (users: number) => string; - unlimited_seats?: string; - month?: string; - year?: string; - wantToPayYearly?: string; - }; - Encryption: { - createEncryptedSession?: string; - sessionNotEncrypted?: string; - sessionEncryptedHaveKeyTooltip?: string; - sessionEncryptedNoKeyTooltip?: string; - sessionEncryptedWrongKeyTooltip?: string; - newEncryptedSessionWarningTitle?: string; - newEncryptedSessionWarningContent?: (key: string) => string; - sessionEncryptionError?: string; - passwordModalTitle?: string; - passwordModelIncorrect?: string; - }; - Private: { - lockSuccessNotification?: string; - unlockSuccessNotification?: string; - lockButton?: string; - unlockButton?: string; - lockDescription?: string; - cancelButton?: string; - sessionLockedTitle?: string; - sessionLockedDescription?: string; - sessionNonProTitle?: string; - sessionNonProDescription?: string; - sessionIsPublic?: string; - sessionIsPrivate?: string; - sessionIsPrivateNoAccess?: string; - }; - TrialPrompt: { - allowanceReachedTitle?: string; - allowanceReachedDescription?: string; - nearEndAllowanceTitle?: string; - nearEndAllowanceDescription?: (quota: number | null) => string; - onTrialTitle?: string; - remainingTrialSentence?: (remaining: string) => string; - trialEndedTitle?: string; - trialEndedSentence?: string; - subscribeNow?: string; - }; - Chat: { - writeAMessage?: string; - }; -} diff --git a/frontend/src/translations/useLanguage.ts b/frontend/src/translations/useLanguage.ts index 35ddd2bf0..66e34c3ee 100644 --- a/frontend/src/translations/useLanguage.ts +++ b/frontend/src/translations/useLanguage.ts @@ -1,13 +1,39 @@ -import LanguageContext from './Context'; -import { useContext, useMemo } from 'react'; +import { useCallback, useContext, useMemo } from 'react'; import languages, { Language } from './languages'; +import { useTranslation } from 'react-i18next'; +import { updateLanguage } from 'api'; +import UserContext from 'auth/Context'; +import { trackEvent } from 'track'; +import { TrackingEvent } from 'common'; -export default function useLanguage(): Language { - const languageContext = useContext(LanguageContext); - const languageIso = languageContext.language; +type UseLanguageResult = [ + language: Language, + changeLanguage: (lng: string) => Promise +]; + +export default function useLanguage(): UseLanguageResult { + const { i18n } = useTranslation(); + const { user, setUser } = useContext(UserContext); + + const locale = i18n.language; const language = useMemo(() => { - const foundLanguage = languages.find((l) => l.value === languageIso); + const foundLanguage = languages.find((l) => l.locale === locale); return foundLanguage || languages[0]; - }, [languageIso]); - return language; + }, [locale]); + + const handleChangeLanguage = useCallback( + async (language: string) => { + trackEvent(`language/change/${language}` as TrackingEvent); + i18n.changeLanguage(language); + if (user) { + const updatedUser = await updateLanguage(language); + if (updatedUser) { + setUser(updatedUser); + } + } + }, + [user, setUser, i18n] + ); + + return [language, handleChangeLanguage]; } diff --git a/frontend/src/translations/useTranslations.ts b/frontend/src/translations/useTranslations.ts deleted file mode 100644 index eb1d9961c..000000000 --- a/frontend/src/translations/useTranslations.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { useContext, useEffect, useState } from 'react'; -import LanguageContext from './Context'; -import { Translation } from './types'; -import merge from 'lodash/merge'; -import cloneDeep from 'lodash/cloneDeep'; - -import en from './en'; - -const fr = () => import('./fr' /* webpackChunkName: 'lang-fr' */); -const hu = () => import('./hu' /* webpackChunkName: 'lang-hu' */); -const ptbr = () => import('./pt-br' /* webpackChunkName: 'lang-pt-br' */); -const pl = () => import('./pl' /* webpackChunkName: 'lang-pl' */); -const nl = () => import('./nl' /* webpackChunkName: 'lang-nl' */); -const ru = () => import('./ru' /* webpackChunkName: 'lang-ru' */); -const zhtw = () => import('./zh-tw' /* webpackChunkName: 'lang-zh-tw' */); -const zhcn = () => import('./zh-cn' /* webpackChunkName: 'lang-zh-cn' */); -const ar = () => import('./ar' /* webpackChunkName: 'lang-ar' */); -const ja = () => import('./ja' /* webpackChunkName: 'lang-ja' */); -const de = () => import('./de' /* webpackChunkName: 'lang-de' */); -const it = () => import('./it' /* webpackChunkName: 'lang-it' */); -const es = () => import('./es' /* webpackChunkName: 'lang-es' */); - -interface Translations { - [key: string]: () => Promise; -} - -const languages: Translations = { - es, - fr, - hu, - pl, - ptbr, - nl, - ru, - zhtw, - zhcn, - ar, - ja, - de, - it, -}; - -export function useLanguage(): [string, (language: string) => void] { - const { language, setLanguage } = useContext(LanguageContext); - return [language, setLanguage]; -} - -function useTranslation() { - const [language] = useLanguage(); - const [merged, setMerged] = useState(en); - - useEffect(() => { - async function load() { - if (language === 'en') { - setMerged(en); - } else { - try { - const { default: translations } = await languages[language](); - setMerged(merge(cloneDeep(en), translations)); - } catch (ex) { - setMerged(en); - } - } - } - load(); - }, [language]); - - return merged; -} - -export default useTranslation; diff --git a/frontend/src/translations/utils.ts b/frontend/src/translations/utils.ts deleted file mode 100644 index 3485076ae..000000000 --- a/frontend/src/translations/utils.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { PluralWord } from './types'; - -export function plural(word: string, pluralForm?: string): PluralWord { - return (n: number): string => { - if (pluralForm) { - return n === 1 ? word : pluralForm; - } - return `${word}${n === 1 ? '' : 's'}`; - }; -} diff --git a/frontend/src/translations/zh-cn.ts b/frontend/src/translations/zh-cn.ts deleted file mode 100644 index 73502b016..000000000 --- a/frontend/src/translations/zh-cn.ts +++ /dev/null @@ -1,404 +0,0 @@ -import { Translation } from './types'; -export default { - Header: { - subtitle: '驾驭敏捷方式的好方法', - logout: '注销', - leave: '离开', - summaryMode: '主旨模式', - account: undefined, - adminPanel: undefined, - }, - LanguagePicker: { - header: '切换语言', - }, - Main: { - hint: '复制并分享网址,即可让别人加入此议程', - }, - Home: { - welcome: undefined, - }, - PreviousGame: { - createdBy: undefined, - posts: undefined, - participants: undefined, - votes: undefined, - actions: undefined, - }, - Column: { - createGroupTooltip: undefined, - }, - Group: { - emptyGroupTitle: '', - emptyGroupContent: '', - }, - Post: { - openExtra: undefined, - closeExtra: undefined, - vote: '投票', - votes: '表决', - deleteButton: '删除', - setActionButton: undefined, - setGiphyButton: undefined, - noContent: '(目前无任何内容)', - by: undefined, - upVote: undefined, - downVote: undefined, - voteRemainingMultiple: undefined, - voteRemainingOne: undefined, - voteRemainingNone: undefined, - toggleGiphyButton: undefined, - }, - Customize: { - title: undefined, - votingCategory: undefined, - votingCategorySub: undefined, - postCategory: undefined, - postCategorySub: undefined, - customTemplateCategory: undefined, - customTemplateCategorySub: undefined, - startButton: undefined, - editButton: undefined, - maxUpVotes: undefined, - maxUpVotesHelp: undefined, - maxDownVotes: undefined, - maxDownVotesHelp: undefined, - maxPosts: undefined, - maxPostsHelp: undefined, - allowSelfVoting: undefined, - allowSelfVotingHelp: undefined, - allowMultipleVotes: undefined, - allowMultipleVotesHelp: undefined, - allowActions: undefined, - allowActionsHelp: undefined, - allowAuthorVisible: undefined, - allowAuthorVisibleHelp: undefined, - newPostsFirst: undefined, - newPostsFirstHelp: undefined, - allowGiphy: undefined, - allowGiphyHelp: undefined, - allowGrouping: undefined, - allowGroupingHelp: undefined, - allowReordering: undefined, - allowReorderingHelp: undefined, - blurCards: undefined, - blurCardsHelp: undefined, - template: undefined, - templateHelp: undefined, - numberOfColumns: undefined, - numberOfColumnsHelp: undefined, - makeDefaultTemplate: undefined, - }, - PostBoard: { - customQuestion: undefined, - notWellQuestion: '哪些已经改善?', - wellQuestion: '哪些做的很好?', - ideasQuestion: '分享优秀的点子?', - startQuestion: undefined, - editButton: undefined, - stopQuestion: undefined, - continueQuestion: undefined, - likedQuestion: undefined, - lackedQuestion: undefined, - learnedQuestion: undefined, - longedForQuestion: undefined, - anchorQuestion: undefined, - boatQuestion: undefined, - islandQuestion: undefined, - windQuestion: undefined, - rockQuestion: undefined, - disconnected: undefined, - reconnect: undefined, - notLoggedIn: undefined, - error: undefined, - maxPostsReached: undefined, - iAmDone: undefined, - iAmNotDoneYet: undefined, - userIsReady: undefined, - }, - GameMenu: { - board: undefined, - summary: undefined, - }, - Template: { - default: undefined, - wellNotWell: undefined, - startStopContinue: undefined, - fourLs: undefined, - sailboat: undefined, - }, - Clients: { - header: '已加入我们的:', - joined: undefined, - left: undefined, - }, - Join: { - welcome: '欢迎 Retrospected', - standardTab: { - header: '创建', - text: '点击以下开始进行回顾:', - button: '创建新的议程', - customizeButton: undefined, - }, - optionsTab: { - header: '高级设定', - input: '名称', - button: '创建议程', - }, - previousTab: { - header: '之前的议程', - rejoinButton: '再次加入', - }, - }, - AnonymousLogin: { - namePlaceholder: '您是谁? 在此输入您的名称', - buttonLabel: '开始!', - header: 'Login', - anonymousAuthHeader: undefined, - anonymousAuthDescription: undefined, - authenticatingWith: undefined, - or: undefined, - }, - SocialMediaLogin: { - header: undefined, - info: undefined, - }, - AuthCommon: { - emailField: undefined, - passwordField: undefined, - nameField: undefined, - passwordScoreWords: undefined, - }, - AccountLogin: { - header: undefined, - loginButton: undefined, - info: undefined, - registerLink: undefined, - forgotPasswordLink: undefined, - errorEmailPasswordIncorrect: undefined, - }, - Register: { - header: undefined, - info: undefined, - registerButton: undefined, - errorAlreadyRegistered: undefined, - errorGeneral: undefined, - messageSuccess: undefined, - errorInvalidEmail: undefined, - }, - ValidateAccount: { - success: undefined, - error: undefined, - loading: undefined, - }, - ResetPassword: { - // Reset Modal - doneMessage: undefined, - header: undefined, - resetButton: undefined, - info: undefined, - // Reset Page - success: undefined, - error: undefined, - loading: undefined, - resetInfo: undefined, - }, - SummaryBoard: { - noPosts: '目前无任何内容', - copyAsMarkdown: undefined, - copyAsRichText: undefined, - copySuccessful: undefined, - }, - SessionName: { - defaultSessionName: '我的回顾', - }, - Invite: { - inviteButton: '邀请', - dialog: { - title: '邀请别人来到您的议程', - text: '邀请别人来到您的议程,只要分享以下的网址给他们', - copyButton: '复制网址到剪贴簿', - }, - }, - Generic: { - ok: 'OK', - cancel: '取消', - }, - Actions: { - tooltip: '在此项目的背面创建一个操作', - label: '打开“操作”面板', - summaryTitle: '你的行动', - title: '行动', - }, - DeleteSession: { - header: undefined, - firstLine: undefined, - secondLine: undefined, - yesImSure: undefined, - cancel: undefined, - }, - RevealCards: { - buttonLabel: undefined, - dialogTitle: undefined, - dialogContent: undefined, - confirmButton: undefined, - cancelButton: undefined, - }, - AccountPage: { - anonymousError: undefined, - details: { - header: undefined, - username: undefined, - email: undefined, - accountType: undefined, - }, - plan: { - header: undefined, - plan: undefined, - youAreOwner: undefined, - youAreMember: undefined, - }, - subscription: { - header: undefined, - manageButton: undefined, - membersEditor: { - title: undefined, - limitReached: undefined, - info: undefined, - }, - }, - trial: { - header: undefined, - yourTrialWillExpireIn: undefined, - subscribe: undefined, - }, - deleteAccount: { - title: undefined, - warning: undefined, - deleteData: undefined, - modal: { - confirm: { - title: undefined, - description: undefined, - confirmation: undefined, - cancellation: undefined, - }, - subheader: undefined, - deleteAccount: undefined, - recommended: undefined, - deleteSessions: { - main: undefined, - selected: undefined, - unselected: undefined, - }, - deletePosts: { - main: undefined, - selected: undefined, - unselected: undefined, - }, - deleteVotes: { - main: undefined, - selected: undefined, - unselected: undefined, - }, - deleteAccountButton: undefined, - cancelButton: undefined, - }, - }, - }, - SubscribePage: { - alertAlreadyPro: undefined, - alertAlreadySubscribed: undefined, - currency: { - title: undefined, - description: undefined, - warning: undefined, - }, - plan: { - title: undefined, - description: undefined, - }, - domain: { - title: undefined, - description: undefined, - invalidDomain: undefined, - }, - subscribe: { - title: undefined, - description: undefined, - cannotRegisterWithAnon: undefined, - checkout: undefined, - }, - }, - SubscribeModal: { - title: undefined, - header: undefined, - description: undefined, - features: { - encryptedSession: { - title: undefined, - description: undefined, - }, - privateSessions: { - title: undefined, - description: undefined, - }, - unlimitedPosts: { - title: undefined, - description: undefined, - }, - }, - subscribeButton: undefined, - payButton: undefined, - cancelButton: undefined, - startTrial: undefined, - }, - Products: { - team: undefined, - unlimited: undefined, - 'self-hosted': undefined, - users: undefined, - unlimited_seats: undefined, - month: undefined, - year: undefined, - wantToPayYearly: undefined, - }, - Encryption: { - createEncryptedSession: undefined, - sessionNotEncrypted: undefined, - sessionEncryptedHaveKeyTooltip: undefined, - sessionEncryptedNoKeyTooltip: undefined, - sessionEncryptedWrongKeyTooltip: undefined, - newEncryptedSessionWarningTitle: undefined, - newEncryptedSessionWarningContent: undefined, - sessionEncryptionError: undefined, - passwordModalTitle: undefined, - passwordModelIncorrect: undefined, - }, - Private: { - lockSuccessNotification: undefined, - unlockSuccessNotification: undefined, - lockButton: undefined, - unlockButton: undefined, - lockDescription: undefined, - cancelButton: undefined, - sessionLockedTitle: undefined, - sessionLockedDescription: undefined, - sessionNonProTitle: undefined, - sessionNonProDescription: undefined, - sessionIsPublic: undefined, - sessionIsPrivate: undefined, - sessionIsPrivateNoAccess: undefined, - }, - TrialPrompt: { - allowanceReachedTitle: undefined, - allowanceReachedDescription: undefined, - nearEndAllowanceTitle: undefined, - nearEndAllowanceDescription: undefined, - onTrialTitle: undefined, - remainingTrialSentence: undefined, - trialEndedTitle: undefined, - trialEndedSentence: undefined, - subscribeNow: undefined, - }, - Chat: { writeAMessage: undefined }, -} as Translation; diff --git a/frontend/src/translations/zh-tw.ts b/frontend/src/translations/zh-tw.ts deleted file mode 100644 index d51cfd22d..000000000 --- a/frontend/src/translations/zh-tw.ts +++ /dev/null @@ -1,404 +0,0 @@ -import { Translation } from './types'; -export default { - Header: { - subtitle: '駕馭敏捷方式的好方法', - logout: '登出', - leave: '離開', - summaryMode: '主旨模式', - account: undefined, - adminPanel: undefined, - }, - LanguagePicker: { - header: '切換語言', - }, - Main: { - hint: '複製並分享網址,即可讓別人加入此議程', - }, - Home: { - welcome: undefined, - }, - PreviousGame: { - createdBy: undefined, - posts: undefined, - participants: undefined, - votes: undefined, - actions: undefined, - }, - Column: { - createGroupTooltip: undefined, - }, - Group: { - emptyGroupTitle: '', - emptyGroupContent: '', - }, - Post: { - openExtra: undefined, - closeExtra: undefined, - vote: '投票', - votes: '表決', - deleteButton: '刪除', - setActionButton: undefined, - setGiphyButton: undefined, - noContent: '(目前無任何內容)', - by: undefined, - upVote: undefined, - downVote: undefined, - voteRemainingMultiple: undefined, - voteRemainingOne: undefined, - voteRemainingNone: undefined, - toggleGiphyButton: undefined, - }, - Customize: { - title: undefined, - votingCategory: undefined, - votingCategorySub: undefined, - postCategory: undefined, - postCategorySub: undefined, - customTemplateCategory: undefined, - customTemplateCategorySub: undefined, - startButton: undefined, - editButton: undefined, - maxUpVotes: undefined, - maxUpVotesHelp: undefined, - maxDownVotes: undefined, - maxDownVotesHelp: undefined, - maxPosts: undefined, - maxPostsHelp: undefined, - allowSelfVoting: undefined, - allowSelfVotingHelp: undefined, - allowMultipleVotes: undefined, - allowMultipleVotesHelp: undefined, - allowActions: undefined, - allowActionsHelp: undefined, - allowAuthorVisible: undefined, - allowAuthorVisibleHelp: undefined, - newPostsFirst: undefined, - newPostsFirstHelp: undefined, - allowGiphy: undefined, - allowGiphyHelp: undefined, - allowGrouping: undefined, - allowGroupingHelp: undefined, - allowReordering: undefined, - allowReorderingHelp: undefined, - blurCards: undefined, - blurCardsHelp: undefined, - template: undefined, - templateHelp: undefined, - numberOfColumns: undefined, - numberOfColumnsHelp: undefined, - makeDefaultTemplate: undefined, - }, - PostBoard: { - customQuestion: undefined, - notWellQuestion: '哪些已經改善?', - wellQuestion: '哪些做的很好?', - ideasQuestion: '分享優秀的點子?', - startQuestion: undefined, - editButton: undefined, - stopQuestion: undefined, - continueQuestion: undefined, - likedQuestion: undefined, - lackedQuestion: undefined, - learnedQuestion: undefined, - longedForQuestion: undefined, - anchorQuestion: undefined, - boatQuestion: undefined, - islandQuestion: undefined, - windQuestion: undefined, - rockQuestion: undefined, - disconnected: undefined, - reconnect: undefined, - notLoggedIn: undefined, - error: undefined, - maxPostsReached: undefined, - iAmDone: undefined, - iAmNotDoneYet: undefined, - userIsReady: undefined, - }, - GameMenu: { - board: undefined, - summary: undefined, - }, - Template: { - default: undefined, - wellNotWell: undefined, - startStopContinue: undefined, - fourLs: undefined, - sailboat: undefined, - }, - Clients: { - header: '已加入我們的:', - joined: undefined, - left: undefined, - }, - Join: { - welcome: '歡迎 Retrospected', - standardTab: { - header: '新增', - text: '點擊以下開始進行回顧:', - button: '建立新的議程', - customizeButton: undefined, - }, - optionsTab: { - header: '進階設定', - input: '名稱', - button: '建立議程', - }, - previousTab: { - header: '之前的議程', - rejoinButton: '再次加入', - }, - }, - AnonymousLogin: { - namePlaceholder: '您是誰? 在此輸入您的名稱', - buttonLabel: '開始!', - header: 'Login', - anonymousAuthHeader: undefined, - anonymousAuthDescription: undefined, - authenticatingWith: undefined, - or: undefined, - }, - SocialMediaLogin: { - header: undefined, - info: undefined, - }, - AuthCommon: { - emailField: undefined, - passwordField: undefined, - nameField: undefined, - passwordScoreWords: undefined, - }, - AccountLogin: { - header: undefined, - loginButton: undefined, - info: undefined, - registerLink: undefined, - forgotPasswordLink: undefined, - errorEmailPasswordIncorrect: undefined, - }, - Register: { - header: undefined, - info: undefined, - registerButton: undefined, - errorAlreadyRegistered: undefined, - errorGeneral: undefined, - messageSuccess: undefined, - errorInvalidEmail: undefined, - }, - ValidateAccount: { - success: undefined, - error: undefined, - loading: undefined, - }, - ResetPassword: { - // Reset Modal - doneMessage: undefined, - header: undefined, - resetButton: undefined, - info: undefined, - // Reset Page - success: undefined, - error: undefined, - loading: undefined, - resetInfo: undefined, - }, - SummaryBoard: { - noPosts: '目前無任何內容', - copyAsMarkdown: undefined, - copyAsRichText: undefined, - copySuccessful: undefined, - }, - SessionName: { - defaultSessionName: '我的回顧', - }, - Invite: { - inviteButton: '邀請', - dialog: { - title: '邀請別人來到您的議程', - text: '邀請別人來到您的議程,只要分享以下的網址給他們', - copyButton: '複製網址到剪貼簿', - }, - }, - Generic: { - ok: 'OK', - cancel: '取消', - }, - Actions: { - tooltip: '在此項目的背面創建一個操作', - label: '打開“操作”面板', - summaryTitle: '你的行動', - title: '行動', - }, - DeleteSession: { - header: undefined, - firstLine: undefined, - secondLine: undefined, - yesImSure: undefined, - cancel: undefined, - }, - RevealCards: { - buttonLabel: undefined, - dialogTitle: undefined, - dialogContent: undefined, - confirmButton: undefined, - cancelButton: undefined, - }, - AccountPage: { - anonymousError: undefined, - details: { - header: undefined, - username: undefined, - email: undefined, - accountType: undefined, - }, - plan: { - header: undefined, - plan: undefined, - youAreOwner: undefined, - youAreMember: undefined, - }, - subscription: { - header: undefined, - manageButton: undefined, - membersEditor: { - title: undefined, - limitReached: undefined, - info: undefined, - }, - }, - trial: { - header: undefined, - yourTrialWillExpireIn: undefined, - subscribe: undefined, - }, - deleteAccount: { - title: undefined, - warning: undefined, - deleteData: undefined, - modal: { - confirm: { - title: undefined, - description: undefined, - confirmation: undefined, - cancellation: undefined, - }, - subheader: undefined, - deleteAccount: undefined, - recommended: undefined, - deleteSessions: { - main: undefined, - selected: undefined, - unselected: undefined, - }, - deletePosts: { - main: undefined, - selected: undefined, - unselected: undefined, - }, - deleteVotes: { - main: undefined, - selected: undefined, - unselected: undefined, - }, - deleteAccountButton: undefined, - cancelButton: undefined, - }, - }, - }, - SubscribePage: { - alertAlreadyPro: undefined, - alertAlreadySubscribed: undefined, - currency: { - title: undefined, - description: undefined, - warning: undefined, - }, - plan: { - title: undefined, - description: undefined, - }, - domain: { - title: undefined, - description: undefined, - invalidDomain: undefined, - }, - subscribe: { - title: undefined, - description: undefined, - cannotRegisterWithAnon: undefined, - checkout: undefined, - }, - }, - SubscribeModal: { - title: undefined, - header: undefined, - description: undefined, - features: { - encryptedSession: { - title: undefined, - description: undefined, - }, - privateSessions: { - title: undefined, - description: undefined, - }, - unlimitedPosts: { - title: undefined, - description: undefined, - }, - }, - subscribeButton: undefined, - payButton: undefined, - cancelButton: undefined, - startTrial: undefined, - }, - Products: { - team: undefined, - unlimited: undefined, - 'self-hosted': undefined, - users: undefined, - unlimited_seats: undefined, - month: undefined, - year: undefined, - wantToPayYearly: undefined, - }, - Encryption: { - createEncryptedSession: undefined, - sessionNotEncrypted: undefined, - sessionEncryptedHaveKeyTooltip: undefined, - sessionEncryptedNoKeyTooltip: undefined, - sessionEncryptedWrongKeyTooltip: undefined, - newEncryptedSessionWarningTitle: undefined, - newEncryptedSessionWarningContent: undefined, - sessionEncryptionError: undefined, - passwordModalTitle: undefined, - passwordModelIncorrect: undefined, - }, - Private: { - lockSuccessNotification: undefined, - unlockSuccessNotification: undefined, - lockButton: undefined, - unlockButton: undefined, - lockDescription: undefined, - cancelButton: undefined, - sessionLockedTitle: undefined, - sessionLockedDescription: undefined, - sessionNonProTitle: undefined, - sessionNonProDescription: undefined, - sessionIsPublic: undefined, - sessionIsPrivate: undefined, - sessionIsPrivateNoAccess: undefined, - }, - TrialPrompt: { - allowanceReachedTitle: undefined, - allowanceReachedDescription: undefined, - nearEndAllowanceTitle: undefined, - nearEndAllowanceDescription: undefined, - onTrialTitle: undefined, - remainingTrialSentence: undefined, - trialEndedTitle: undefined, - trialEndedSentence: undefined, - subscribeNow: undefined, - }, - Chat: { writeAMessage: undefined }, -} as Translation; diff --git a/frontend/src/utils/getConfig.ts b/frontend/src/utils/getConfig.ts index bed216c0f..951b6f2a5 100644 --- a/frontend/src/utils/getConfig.ts +++ b/frontend/src/utils/getConfig.ts @@ -51,12 +51,19 @@ function getConfig(): Config { const sentryUrl = getKey('SENTRY_URL', 'NO_SENTRY'); const giphyApiKey = getKey('GIPHY_API_KEY', 'NO_GIPHY'); const stripeKey = getKey('STRIPE_KEY', 'NO_STRIPE'); - const defaultLanguage = getKey( + let defaultLanguage = getKey( 'DEFAULT_LANGUAGE', 'NO_DEFAULT_LANGUAGE', - 'en' + 'en-GB' ); + if (defaultLanguage.length !== 5) { + console.error( + 'Your default language (DEFAULT_LANGUAGE) is not in the right format. The right format should be a string of 5 characters, for example: en-GB, fr-FR, etc.' + ); + defaultLanguage = 'en-GB'; + } + return { hasGA: !!googleAnalyticsId, hasSentry: !!sentryUrl, diff --git a/frontend/src/views/Game.tsx b/frontend/src/views/Game.tsx index 7c7e5b126..9a357a82f 100644 --- a/frontend/src/views/Game.tsx +++ b/frontend/src/views/Game.tsx @@ -15,7 +15,7 @@ import Tab from '@mui/material/Tab'; import Button from '@mui/material/Button'; import { colors } from '@mui/material'; import { Dashboard, List, CloudOff } from '@mui/icons-material'; -import useTranslations from '../translations'; +import { useTranslation } from 'react-i18next'; import useGame from './game/useGame'; import Board from './game/board/Board'; import SummaryMode from './game/summary/SummaryMode'; @@ -34,10 +34,9 @@ interface RouteParams { } function GamePage() { - const { GameMenu, PostBoard } = useTranslations(); const { pathname, hash } = useLocation(); const navigate = useNavigate(); - const translations = useTranslations(); + const { t } = useTranslation(); const { gameId } = useParams(); const { session } = useSession(); const handleChange = useCallback( @@ -100,13 +99,13 @@ function GamePage() {
- {decrypt(session.name) || translations.SessionName.defaultSessionName}{' '} - - Retrospected + {decrypt(session.name) || t('SessionName.defaultSessionName')} - + Retrospected -  {PostBoard.disconnected} +  {t('PostBoard.disconnected')} ) : null} @@ -139,10 +138,14 @@ function GamePage() { aria-label="Game mode tabs" allowScrollButtonsMobile > - } value={rootUrl} /> + } + value={rootUrl} + /> {!session.options.blurCards ? ( } value={summaryUrl} /> diff --git a/frontend/src/views/Home.tsx b/frontend/src/views/Home.tsx index e33de179b..f33ec9c91 100644 --- a/frontend/src/views/Home.tsx +++ b/frontend/src/views/Home.tsx @@ -5,7 +5,6 @@ import Fab from '@mui/material/Fab'; import { makeStyles } from '@mui/styles'; import { colors } from '@mui/material'; import { Lock, ThumbUpAlt } from '@mui/icons-material'; -import useTranslations from '../translations'; import PreviousGames from './home/PreviousGames'; import { SessionMetadata } from 'common'; import { trackEvent } from './../track'; @@ -19,6 +18,7 @@ import ProButton from '../components/ProButton'; import { useSnackbar } from 'notistack'; import TrialPrompt from './home/TrialPrompt'; import HowDoesItWorkButton from '../components/HowDoesItWorkButton'; +import { useTranslation } from 'react-i18next'; const useStyles = makeStyles({ media: { @@ -38,7 +38,7 @@ function Home() { const navigate = useNavigate(); const user = useUser(); const isLoggedIn = !!user; - const translations = useTranslations(); + const { t } = useTranslation(); const { enqueueSnackbar } = useSnackbar(); const [previousSessions, refreshPreviousSessions] = usePreviousSessions(); const hasPreviousSessions = previousSessions.length > 0; @@ -83,7 +83,7 @@ function Home() { <> - {translations.Home.welcome!(user?.name || '')} + {t('Home.welcome', { name: user?.name || '' })} @@ -96,7 +96,7 @@ function Home() { data-cy="new-session-button" > - {translations.Join.standardTab.button} + {t('Join.standardTab.button')}
@@ -110,7 +110,7 @@ function Home() { disabled={!isLoggedIn} > - {translations.Encryption.createEncryptedSession} + {t('Encryption.createEncryptedSession')} @@ -118,7 +118,7 @@ function Home() { {hasPreviousSessions ? ( <> - {translations.Join.previousTab.header} + {t('Join.previousTab.header')} - - - - } /> - - + + {hasParticipants ? : null} diff --git a/frontend/src/views/Reset.tsx b/frontend/src/views/Reset.tsx index b90d532a6..23846f062 100644 --- a/frontend/src/views/Reset.tsx +++ b/frontend/src/views/Reset.tsx @@ -7,7 +7,7 @@ import UserContext from '../auth/Context'; import Input from '../components/Input'; import { VpnKey } from '@mui/icons-material'; import Button from '@mui/material/Button'; -import useTranslations from '../translations'; +import { useTranslation } from 'react-i18next'; const PasswordStrength = lazy( () => @@ -20,8 +20,7 @@ function ResetPasswordPage() { const { setUser } = useContext(UserContext); const navigate = useNavigate(); const location = useLocation(); - const { ResetPassword: translations, AuthCommon: authTranslations } = - useTranslations(); + const { t } = useTranslation(); const params = new URLSearchParams(location.search); const email = params.get('email'); const code = params.get('code'); @@ -53,22 +52,22 @@ function ResetPasswordPage() { return (
{success === true && !loading ? ( - {translations.success} + {t('ResetPassword.success')} ) : null} {success === false && !loading ? ( - {translations.error} + {t('ResetPassword.error')} ) : null} {success === null && loading ? ( - {translations.loading} + {t('ResetPassword.loading')} ) : null} {success === null && !loading ? ( <> - {translations.resetInfo} + {t('ResetPassword.resetInfo')} ) : null} diff --git a/frontend/src/views/Validate.tsx b/frontend/src/views/Validate.tsx index 688b9716b..d4e278133 100644 --- a/frontend/src/views/Validate.tsx +++ b/frontend/src/views/Validate.tsx @@ -5,13 +5,13 @@ import { verifyEmail } from '../api'; import { Alert } from '@mui/material'; import { useContext } from 'react'; import UserContext from '../auth/Context'; -import useTranslations from '../translations'; +import { useTranslation } from 'react-i18next'; function ValidatePage() { const { setUser } = useContext(UserContext); const navigate = useNavigate(); const location = useLocation(); - const { ValidateAccount: translations } = useTranslations(); + const { t } = useTranslation(); const params = new URLSearchParams(location.search); const email = params.get('email'); const code = params.get('code'); @@ -42,12 +42,14 @@ function ValidatePage() { return (
{success && !loading ? ( - {translations.success} + {t('ValidateAccount.success')} ) : null} {!success && !loading ? ( - {translations.error} + {t('ValidateAccount.error')} + ) : null} + {loading ? ( + {t('ValidateAccount.loading')} ) : null} - {loading ? {translations.loading} : null}
); } diff --git a/frontend/src/views/account/AccountPage.tsx b/frontend/src/views/account/AccountPage.tsx index b34f5a6ac..e4422e396 100644 --- a/frontend/src/views/account/AccountPage.tsx +++ b/frontend/src/views/account/AccountPage.tsx @@ -7,7 +7,7 @@ import ProPill from '../../components/ProPill'; import { Alert } from '@mui/material'; import Section from './Section'; import MembersEditor from './MembersEditor'; -import useTranslations from '../../translations'; +import { useTranslation } from 'react-i18next'; import { useNavigate } from 'react-router-dom'; import useIsTrial from '../../auth/useIsTrial'; import TrialPrompt from '../home/TrialPrompt'; @@ -21,8 +21,7 @@ function AccountPage() { const isTrial = useIsTrial(); const formatDistanceToNow = useFormatDate(); const navigate = useNavigate(); - const { AccountPage: translations, SubscribePage: subscribeTranslations } = - useTranslations(); + const { t } = useTranslation(); const [deleteModalOpen, handleDeleteModalOpen, handleDeleteModalClose] = useModal(); @@ -40,7 +39,7 @@ function AccountPage() { } if (user.accountType === 'anonymous') { - return {translations.anonymousError}; + return {t('AccountPage.anonymousError')}; } return ( @@ -52,53 +51,55 @@ function AccountPage() { -
+
- {translations.details?.username} + {t('AccountPage.details.username')} {user.username} - {translations.details?.email} + {t('AccountPage.details.email')} {user.email} - {translations.details?.accountType} + {t('AccountPage.details.accountType')} {user.accountType}
{user.plan ? ( -
+
- {translations.plan?.plan} + {t('AccountPage.plan.plan')} {user.plan} {user.domain ? ( - {subscribeTranslations.domain.title} + {t('SubscribePage.domain.title')} {user.domain} ) : null} {onSomebodysPlan && ( - {translations.plan?.youAreMember} + + {t('AccountPage.plan.youAreMember')} + )} {ownsThePlan && ( - {translations.plan?.youAreOwner} + {t('AccountPage.plan.youAreOwner')} )}
) : null} {ownsThePlan && user && user.plan && user.plan === 'team' ? ( -
+
) : null} {ownsThePlan && !isTrial ? ( -
+
{url ? ( ) : null}
) : null} {isTrial ? ( -
+
- {translations.trial.yourTrialWillExpireIn!( - formatDistanceToNow(new Date(user.trial!)) - )} + {t('AccountPage.trial.yourTrialWillExpireIn', { + date: formatDistanceToNow(new Date(user.trial!)), + })}
) : null} -
- {translations.deleteAccount.warning} +
+ + {t('AccountPage.deleteAccount.warning')} + ( '/api/stripe/members', @@ -78,13 +78,15 @@ function MembersEditor() { {!isNotFull(members) ? ( - {translations.subscription!.membersEditor!.limitReached!( - MAX_MEMBERS + 1 - )} + {t('AccountPage.subscription.membersEditor.limitReached', { + limit: MAX_MEMBERS + 1, + })} ) : ( - {translations.subscription!.membersEditor!.info!(MAX_MEMBERS)} + {t('AccountPage.subscription.membersEditor.info', { + limit: MAX_MEMBERS, + })} )} { if (!user) { @@ -71,10 +67,14 @@ export function DeleteModal({ 'data-cy': 'delete-modal-confirm', }; confirm({ - title: translations.confirm.title, - description: translations.confirm.description, - confirmationText: translations.confirm.confirmation, - cancellationText: translations.confirm.cancellation, + title: t('AccountPage.deleteAccount.modal.confirm.title'), + description: t('AccountPage.deleteAccount.modal.confirm.description'), + confirmationText: t( + 'AccountPage.deleteAccount.modal.confirm.confirmation' + ), + cancellationText: t( + 'AccountPage.deleteAccount.modal.confirm.cancellation' + ), confirmationButtonProps: buttonProps as any, }) .then(async () => { @@ -124,7 +124,7 @@ export function DeleteModal({ confirm, onClose, onDelete, - translations, + t, enqueueSnackbar, ]); @@ -142,10 +142,14 @@ export function DeleteModal({ > {translations.subheader}} + subheader={ + + {t('AccountPage.deleteAccount.modal.subheader')} + + } > }> - {translations.deleteAccount} ({user.email}) + {t('AccountPage.deleteAccount.modal.deleteAccount')} ({user.email}) } cy="delete-modal-sessions" > -

{translations.deleteSessions.main}

+

{t('AccountPage.deleteAccount.modal.deleteSessions.main')}

{deleteSessions ? ( - {translations.deleteSessions.selected} + + {t('AccountPage.deleteAccount.modal.deleteSessions.selected')} + ) : ( - {translations.recommended} -{' '} - {translations.deleteSessions.unselected} + {t('AccountPage.deleteAccount.modal.recommended')} -{' '} + {t('AccountPage.deleteAccount.modal.deleteSessions.unselected')} )}
@@ -169,13 +175,15 @@ export function DeleteModal({ icon={} cy="delete-modal-posts" > -

{translations.deletePosts.main}

+

{t('AccountPage.deleteAccount.modal.deletePosts.main')}

{deletePosts ? ( - {translations.deletePosts.selected} + + {t('AccountPage.deleteAccount.modal.deletePosts.selected')} + ) : ( - {translations.recommended} -{' '} - {translations.deletePosts.unselected} + {t('AccountPage.deleteAccount.modal.recommended')} -{' '} + {t('AccountPage.deleteAccount.modal.deletePosts.unselected')} )} @@ -185,13 +193,15 @@ export function DeleteModal({ icon={} cy="delete-modal-votes" > -

{translations.deleteVotes.main}

+

{t('AccountPage.deleteAccount.modal.deleteVotes.main')}

{deleteVotes ? ( - {translations.deleteVotes.selected} + + {t('AccountPage.deleteAccount.modal.deleteVotes.selected')} + ) : ( - {translations.recommended} -{' '} - {translations.deleteVotes.unselected} + {t('AccountPage.deleteAccount.modal.recommended')} -{' '} + {t('AccountPage.deleteAccount.modal.deleteVotes.unselected')} )} @@ -204,9 +214,11 @@ export function DeleteModal({ onClick={handleDelete} data-cy="delete-modal-delete-button" > - {translations.deleteAccountButton} + {t('AccountPage.deleteAccount.modal.deleteAccountButton')} + + - ); diff --git a/frontend/src/views/admin/NewAccountModal.tsx b/frontend/src/views/admin/NewAccountModal.tsx index 6fa624359..78018a485 100644 --- a/frontend/src/views/admin/NewAccountModal.tsx +++ b/frontend/src/views/admin/NewAccountModal.tsx @@ -7,13 +7,14 @@ import { DialogContent, DialogTitle, } from '@mui/material'; -import useTranslations, { useLanguage } from '../../translations'; +import { useLanguage } from '../../translations'; import Input from '../../components/Input'; import { Person, Email, VpnKey } from '@mui/icons-material'; import { addUser } from '../../api'; import { validate } from 'isemail'; import useBackendCapabilities from 'global/useBackendCapabilities'; import { FullUser } from 'common'; +import { useTranslation } from 'react-i18next'; type NewAccountModalProps = { open: boolean; @@ -33,9 +34,8 @@ export function NewAccountModal({ onAdd, onClose, }: NewAccountModalProps) { - const { Register: translations, AuthCommon: authTranslations } = - useTranslations(); - const language = useLanguage(); + const { t } = useTranslation(); + const [language] = useLanguage(); const [registerName, setRegisterName] = useState(''); const [registerEmail, setRegisterEmail] = useState(''); const [registerPassword, setRegisterPassword] = useState(''); @@ -55,15 +55,15 @@ export function NewAccountModal({ registerName, registerEmail, registerPassword, - language.value + language.locale ); if (response.error) { switch (response.error) { case 'already-exists': - setGeneralError(translations.errorAlreadyRegistered!); + setGeneralError(t('Register.errorAlreadyRegistered')!); return; default: - setGeneralError(translations.errorGeneral!); + setGeneralError(t('Register.errorGeneral')!); return; } } else if (response.user) { @@ -76,9 +76,8 @@ export function NewAccountModal({ registerName, registerEmail, registerPassword, - language.value, - translations, - + language.locale, + t, onAdd, ]); @@ -96,7 +95,7 @@ export function NewAccountModal({ Create a new user {isSuccessful ? ( - {translations.messageSuccess} + {t('Register.messageSuccess')} ) : ( <> {!!generalError ? ( @@ -129,7 +128,7 @@ export function NewAccountModal({ error={!validEmail && registerEmail.length > 0} helperText={ !validEmail && registerEmail.length > 0 - ? translations.errorInvalidEmail + ? t('Register.errorInvalidEmail') : undefined } /> @@ -149,8 +148,8 @@ export function NewAccountModal({ diff --git a/frontend/src/views/game/GameFooter.tsx b/frontend/src/views/game/GameFooter.tsx index 95acc64e5..5650fa3a6 100644 --- a/frontend/src/views/game/GameFooter.tsx +++ b/frontend/src/views/game/GameFooter.tsx @@ -12,12 +12,12 @@ import useParticipants from './useParticipants'; import useSession from './useSession'; import styled from '@emotion/styled'; import useUser from '../../auth/useUser'; -import useTranslation from '../../translations/useTranslations'; import { useCallback, useEffect, useState } from 'react'; import { trackEvent } from '../../track'; import { Message } from 'common'; import useModal from '../../hooks/useModal'; import ChatModal from './chat/ChatModal'; +import { useTranslation } from 'react-i18next'; type GameFooterProps = { onReady: () => void; @@ -29,7 +29,7 @@ function GameFooter({ onReady, onMessage, messages }: GameFooterProps) { const { participants } = useParticipants(); const { session } = useSession(); const user = useUser(); - const { PostBoard: translations } = useTranslation(); + const { t } = useTranslation(); const isUserReady = !!user && !!session && session.ready.includes(user.id); const fullScreen = useMediaQuery('(min-width:600px)'); const [chatOpen, openChat, closeChat] = useModal(); @@ -95,7 +95,9 @@ function GameFooter({ onReady, onMessage, messages }: GameFooterProps) { ) } > - {isUserReady ? translations.iAmNotDoneYet : translations.iAmDone} + {isUserReady + ? t('PostBoard.iAmNotDoneYet').toString() + : t('PostBoard.iAmDone').toString()} ) : null} {user ? ( diff --git a/frontend/src/views/game/Unauthorized.tsx b/frontend/src/views/game/Unauthorized.tsx index 3c7a4f938..b1abc6575 100644 --- a/frontend/src/views/game/Unauthorized.tsx +++ b/frontend/src/views/game/Unauthorized.tsx @@ -1,6 +1,6 @@ import { AccessErrorType } from 'common'; import NoContent from '../../components/NoContent'; -import useTranslations from '../../translations'; +import { useTranslation } from 'react-i18next'; interface UnauthorizedProps { reason?: AccessErrorType; @@ -17,17 +17,17 @@ interface Errors { } function useGetErrors(reason?: AccessErrorType): Errors { - const translations = useTranslations(); + const { t } = useTranslation(); switch (reason) { case 'locked': return { - title: translations.Private.sessionLockedTitle!, - subtitle: translations.Private.sessionLockedDescription!, + title: t('Private.sessionLockedTitle')!, + subtitle: t('Private.sessionLockedDescription')!, }; case 'non_pro': return { - title: translations.Private.sessionNonProTitle!, - subtitle: translations.Private.sessionNonProDescription!, + title: t('Private.sessionNonProTitle')!, + subtitle: t('Private.sessionNonProDescription')!, }; } diff --git a/frontend/src/views/game/board/Column.tsx b/frontend/src/views/game/board/Column.tsx index 6644586c3..daea7d901 100644 --- a/frontend/src/views/game/board/Column.tsx +++ b/frontend/src/views/game/board/Column.tsx @@ -8,7 +8,7 @@ import { colors } from '@mui/material'; import { CreateNewFolder, SubdirectoryArrowLeft } from '@mui/icons-material'; import PostItem from './post/Post'; import { Post, PostGroup } from 'common'; -import useTranslations from '../../../translations'; +import { useTranslation } from 'react-i18next'; import Group from './Group'; import { Droppable, @@ -55,7 +55,7 @@ const Column: React.FC = ({ onEditGroup, onDeleteGroup, }) => { - const { Column: columnTranslations } = useTranslations(); + const { t } = useTranslation(); const [content, setContent] = useState(''); const { encrypt } = useCrypto(); const permissions = useSessionUserPermissions(); @@ -113,7 +113,7 @@ const Column: React.FC = ({ /> {permissions.canCreateGroup ? ( - + diff --git a/frontend/src/views/game/board/Group.tsx b/frontend/src/views/game/board/Group.tsx index cdc9c550f..7baa586f0 100644 --- a/frontend/src/views/game/board/Group.tsx +++ b/frontend/src/views/game/board/Group.tsx @@ -16,7 +16,7 @@ import { } from '@mui/icons-material'; import EditableLabel from '../../../components/EditableLabel'; import { Alert, AlertTitle } from '@mui/material'; -import useTranslations from '../../../translations'; +import { useTranslation } from 'react-i18next'; import useCrypto from '../../../crypto/useCrypto'; import { Badge } from '@mui/material'; @@ -34,7 +34,7 @@ export default function Group({ readonly, children, }: PropsWithChildren) { - const { Group: groupTranslations } = useTranslations(); + const { t } = useTranslation(); const [collapsed, setCollapsed] = useState(false); const { decrypt, encrypt } = useCrypto(); const handleEditLabel = useCallback( @@ -94,8 +94,8 @@ export default function Group({ {group.posts.length === 0 ? ( - {groupTranslations.emptyGroupTitle} - {groupTranslations.emptyGroupContent} + {t('Group.emptyGroupTitle')} + {t('Group.emptyGroupContent')} ) : null} diff --git a/frontend/src/views/game/board/header/BoardHeader.tsx b/frontend/src/views/game/board/header/BoardHeader.tsx index 58dd6a687..8d0af79a2 100644 --- a/frontend/src/views/game/board/header/BoardHeader.tsx +++ b/frontend/src/views/game/board/header/BoardHeader.tsx @@ -3,7 +3,7 @@ import styled from '@emotion/styled'; import { SessionOptions, ColumnDefinition } from 'common'; import Typography from '@mui/material/Typography'; import { makeStyles } from '@mui/styles'; -import useTranslations from '../../../../translations'; +import { useTranslation } from 'react-i18next'; import useRemainingVotes from './useRemainingVotes'; import useCanReveal from './useCanReveal'; import EditableLabel from '../../../../components/EditableLabel'; @@ -51,7 +51,7 @@ function BoardHeader({ onLockSession, onRenameSession, }: BoardHeaderProps) { - const translations = useTranslations(); + const { t } = useTranslation(); const classes = useStyles(); const [key] = useEncryptionKey(); const remainingVotes = useRemainingVotes(); @@ -91,24 +91,18 @@ function BoardHeader({ <> {!canDecrypt ? : null} {!isLoggedIn ? ( - {translations.PostBoard.notLoggedIn} + {t('PostBoard.notLoggedIn')} ) : null} {!canDecrypt ? ( - - {translations.Encryption.sessionEncryptionError} - + {t('Encryption.sessionEncryptionError')} ) : null} {permissions.hasReachedMaxPosts ? ( - - {translations.PostBoard.maxPostsReached} - + {t('PostBoard.maxPostsReached')} ) : null} {isDisabled ? ( - - {translations.TrialPrompt.allowanceReachedTitle} - - {translations.TrialPrompt.allowanceReachedDescription} + {t('TrialPrompt.allowanceReachedTitle')} + {t('TrialPrompt.allowanceReachedDescription')} ) : null} @@ -130,7 +124,7 @@ function BoardHeader({ className={classes.sessionName} > - {translations.Encryption.newEncryptedSessionWarningContent!( - key || '(unknown)' - )} + {t('Encryption.newEncryptedSessionWarningContent', { + key: key || '(unknown)', + })} ) : null} diff --git a/frontend/src/views/game/board/header/EncryptionModal.tsx b/frontend/src/views/game/board/header/EncryptionModal.tsx index 10bc17024..fdce7e5ff 100644 --- a/frontend/src/views/game/board/header/EncryptionModal.tsx +++ b/frontend/src/views/game/board/header/EncryptionModal.tsx @@ -10,8 +10,8 @@ import { Alert } from '@mui/material'; import { useEncryptionKey } from '../../../../crypto/useEncryptionKey'; import { useNavigate, useLocation } from 'react-router-dom'; import { colors } from '@mui/material'; -import useTranslation from '../../../../translations/useTranslations'; import useSession from '../../useSession'; +import { useTranslation } from 'react-i18next'; function EncryptionModal() { const [password, setPassword] = useState(''); @@ -19,7 +19,7 @@ function EncryptionModal() { const storeKey = useEncryptionKey()[1]; const navigate = useNavigate(); const location = useLocation(); - const { Encryption: translations } = useTranslation(); + const { t } = useTranslation(); const isCorrectPassword = useMemo(() => { if (session && session.encrypted) { return decrypt(session.encrypted, password) === CHECK_PREFIX; @@ -40,7 +40,7 @@ function EncryptionModal() { }, [isCorrectPassword, password, storeKey, location, navigate]); return ( - {translations.passwordModalTitle} + {t('Encryption.passwordModalTitle')} @@ -48,7 +48,7 @@ function EncryptionModal() { {!isCorrectPassword && password.length ? ( - {translations.passwordModelIncorrect} + {t('Encryption.passwordModelIncorrect')} ) : null} diff --git a/frontend/src/views/game/board/header/LockSession.tsx b/frontend/src/views/game/board/header/LockSession.tsx index ef897d4fb..c6a2776ca 100644 --- a/frontend/src/views/game/board/header/LockSession.tsx +++ b/frontend/src/views/game/board/header/LockSession.tsx @@ -11,7 +11,7 @@ import { useCallback, useState } from 'react'; import styled from '@emotion/styled'; import CustomAvatar from '../../../../components/Avatar'; import { useSnackbar } from 'notistack'; -import useTranslations from '../../../../translations'; +import { useTranslation } from 'react-i18next'; import ProButton from '../../../../components/ProButton'; import useParticipants from '../../useParticipants'; import useSession from '../../useSession'; @@ -24,7 +24,7 @@ function LockSession({ onLock }: LockSessionProps) { const { session } = useSession(); const [open, setOpen] = useState(false); const { enqueueSnackbar } = useSnackbar(); - const { Private: translations } = useTranslations(); + const { t } = useTranslation(); const { participants } = useParticipants(); const fullScreen = useMediaQuery('(max-width:600px)'); @@ -33,13 +33,13 @@ function LockSession({ onLock }: LockSessionProps) { onLock(!session.locked); enqueueSnackbar( session.locked - ? translations.unlockSuccessNotification - : translations.lockSuccessNotification, + ? t('Private.unlockSuccessNotification') + : t('Private.lockSuccessNotification'), { variant: 'success' } ); } setOpen(false); - }, [session, onLock, enqueueSnackbar, translations]); + }, [session, onLock, enqueueSnackbar, t]); const handleOpenDialog = useCallback(() => { if (session && !session.locked) { @@ -72,7 +72,7 @@ function LockSession({ onLock }: LockSessionProps) { } onClick={handleOpenDialog} > - {session.locked ? translations.unlockButton : translations.lockButton} + {session.locked ? t('Private.unlockButton') : t('Private.lockButton')} -  {translations.lockButton} +  {t('Private.lockButton')} - {translations.lockDescription} + {t('Private.lockDescription')} @@ -102,10 +102,10 @@ function LockSession({ onLock }: LockSessionProps) { diff --git a/frontend/src/views/game/board/header/ModifyOptions.tsx b/frontend/src/views/game/board/header/ModifyOptions.tsx index 8d7ae3220..0710521a2 100644 --- a/frontend/src/views/game/board/header/ModifyOptions.tsx +++ b/frontend/src/views/game/board/header/ModifyOptions.tsx @@ -6,7 +6,7 @@ import { SessionOptions, ColumnDefinition } from 'common'; import { toColumnDefinitions } from '../../../../state/columns'; import { trackEvent } from '../../../../track'; import { Settings } from '@mui/icons-material'; -import useTranslations from '../../../../translations'; +import { useTranslation } from 'react-i18next'; import useSession from '../../useSession'; interface ModifyOptionsProps { @@ -23,7 +23,7 @@ function ModifyOptions({ onEditColumns, onSaveTemplate, }: ModifyOptionsProps) { - const { Join } = useTranslations(); + const { t } = useTranslation(); const [open, setOpen] = useState(false); const { session } = useSession(); @@ -68,7 +68,7 @@ function ModifyOptions({ startIcon={} onClick={() => setOpen(true)} > - {Join.standardTab.customizeButton} + {t('Join.standardTab.customizeButton')} {open ? ( { - const translations = useTranslations(); + const { t } = useTranslation(); const { session } = useSession(); const hideUpVotes = session?.options.maxUpVotes === 0; const hideDownVotes = session?.options.maxDownVotes === 0; @@ -23,7 +24,7 @@ const RemainingVotes = ({ up, down }: RemainingVotesProps) => { return ( {up !== null && !hideUpVotes ? ( - + 0 ? 'primary' : 'error'} @@ -33,10 +34,7 @@ const RemainingVotes = ({ up, down }: RemainingVotesProps) => { ) : null} {down !== null && !hideDownVotes ? ( - + 0 ? 'primary' : 'error'} @@ -50,21 +48,24 @@ const RemainingVotes = ({ up, down }: RemainingVotesProps) => { }; function getTooltip( - translations: Translation, + t: TranslationFunction, value: number, type: 'up' | 'down' ) { - const t = translations.Post; if (value === 0) { - return t.voteRemainingNone!(type === 'up' ? t.upVote! : t.downVote!); + return t('Post.voteRemainingNone', { + type: type === 'up' ? t('Post.upVote') : t('Post.downVote'), + }); } if (value === 1) { - return t.voteRemainingOne!(type === 'up' ? t.upVote! : t.downVote!); + return t('Post.voteRemainingOne', { + type: type === 'up' ? t('Post.upVote') : t('Post.downVote'), + }); } - return t.voteRemainingMultiple!( - value, - type === 'up' ? t.upVote! : t.downVote! - ); + return t('Post.voteRemainingMultiple', { + number: value, + type: type === 'up' ? t('Post.upVote') : t('Post.downVote'), + }); } const Container = styled.div` diff --git a/frontend/src/views/game/board/header/RevealButton.tsx b/frontend/src/views/game/board/header/RevealButton.tsx index 74e9858ca..df2faeb45 100644 --- a/frontend/src/views/game/board/header/RevealButton.tsx +++ b/frontend/src/views/game/board/header/RevealButton.tsx @@ -6,14 +6,14 @@ import DialogContent from '@mui/material/DialogContent'; import DialogContentText from '@mui/material/DialogContentText'; import DialogTitle from '@mui/material/DialogTitle'; import { Visibility } from '@mui/icons-material'; -import useTranslation from '../../../../translations/useTranslations'; +import { useTranslation } from 'react-i18next'; interface RevealButtonProps { onClick: () => void; } function RevealButton({ onClick }: RevealButtonProps) { - const { RevealCards } = useTranslation(); + const { t } = useTranslation(); const [revealDialogOpen, setRevealDialogOpen] = useState(false); const handleOpenDialog = useCallback(() => { setRevealDialogOpen(true); @@ -29,7 +29,7 @@ function RevealButton({ onClick }: RevealButtonProps) { startIcon={} onClick={handleOpenDialog} > - {RevealCards.buttonLabel} + {t('RevealCards.buttonLabel')} - {RevealCards.dialogTitle} + {t('RevealCards.dialogTitle')} - {RevealCards.dialogContent} + + {t('RevealCards.dialogContent')} + diff --git a/frontend/src/views/game/board/post/Post.tsx b/frontend/src/views/game/board/post/Post.tsx index fb4cd47dd..027524e98 100644 --- a/frontend/src/views/game/board/post/Post.tsx +++ b/frontend/src/views/game/board/post/Post.tsx @@ -19,7 +19,7 @@ import { EmojiEmotionsOutlined, } from '@mui/icons-material'; import { Draggable, DraggableProvided } from 'react-beautiful-dnd'; -import useTranslations from '../../../../translations'; +import { useTranslation } from 'react-i18next'; import EditableLabel from '../../../../components/EditableLabel'; import { Palette } from '../../../../Theme'; import { Post } from 'common'; @@ -91,7 +91,7 @@ const PostItem = ({ isBlurred, } = usePostUserPermissions(post); const classes = useStyles(); - const { Actions: translations, Post: postTranslations } = useTranslations(); + const { t } = useTranslation(); const { encrypt, decrypt } = useCrypto(); const canDecrypt = useCanDecrypt(); const [giphyImageUrl, showGiphyImage, toggleShowGiphyImage] = useGiphy( @@ -187,7 +187,7 @@ const PostItem = ({ color="textSecondary" component="div" > - {postTranslations.by}  + {t('Post.by')}  {displayAction && canCreateAction && ( - {translations.title}: + {t('Actions.title')}: @@ -227,8 +227,8 @@ const PostItem = ({ <> {giphyImageUrl && ( @@ -258,8 +258,8 @@ const PostItem = ({ )} {canEdit && config.hasGiphy && canUseGiphy && ( } @@ -269,8 +269,8 @@ const PostItem = ({ )} {canDelete && ( { return sortBy(messages, (m) => m.created); @@ -35,7 +35,7 @@ export default function Chat({ messages, onMessage }: ChatProps) { diff --git a/frontend/src/views/game/summary/SpeedDial.tsx b/frontend/src/views/game/summary/SpeedDial.tsx index 92acf7cfd..afbb5970b 100644 --- a/frontend/src/views/game/summary/SpeedDial.tsx +++ b/frontend/src/views/game/summary/SpeedDial.tsx @@ -6,12 +6,12 @@ import { AssignmentReturned, SaveAlt } from '@mui/icons-material'; import SvgIcon from '@mui/material/SvgIcon'; import useMarkdown from './useMarkdown'; import ReactMarkdown from 'react-markdown'; -import useTranslations from '../../../translations'; +import { useTranslation } from 'react-i18next'; import { useSnackbar } from 'notistack'; const CopySpeedDial = () => { const isSupported = !!window.getSelection; - const { SummaryBoard } = useTranslations(); + const { t } = useTranslation(); const [open, setOpen] = useState(false); const { enqueueSnackbar } = useSnackbar(); const handleOpen = useCallback(() => setOpen(true), []); @@ -24,14 +24,14 @@ const CopySpeedDial = () => { p.innerText = md; copyToClipboard(p); setOpen(false); - enqueueSnackbar(SummaryBoard.copySuccessful, { variant: 'success' }); - }, [md, SummaryBoard.copySuccessful, enqueueSnackbar]); + enqueueSnackbar(t('SummaryBoard.copySuccessful'), { variant: 'success' }); + }, [md, t, enqueueSnackbar]); const handleCopyRichText = useCallback(() => { copyToClipboard(mdElement.current!); setOpen(false); - enqueueSnackbar(SummaryBoard.copySuccessful, { variant: 'success' }); - }, [SummaryBoard.copySuccessful, enqueueSnackbar]); + enqueueSnackbar(t('SummaryBoard.copySuccessful'), { variant: 'success' }); + }, [t, enqueueSnackbar]); return isSupported ? ( <> @@ -47,12 +47,12 @@ const CopySpeedDial = () => { > } - tooltipTitle={SummaryBoard.copyAsRichText!} + tooltipTitle={t('SummaryBoard.copyAsRichText')} onClick={handleCopyRichText} /> } - tooltipTitle={SummaryBoard.copyAsMarkdown!} + tooltipTitle={t('SummaryBoard.copyAsMarkdown')} onClick={handleCopyToMarkdown} /> diff --git a/frontend/src/views/game/summary/SummaryMode.tsx b/frontend/src/views/game/summary/SummaryMode.tsx index d58dd8ed8..179fb3150 100644 --- a/frontend/src/views/game/summary/SummaryMode.tsx +++ b/frontend/src/views/game/summary/SummaryMode.tsx @@ -14,12 +14,11 @@ import { colors } from '@mui/material'; import { Feedback } from '@mui/icons-material'; import { ColumnContent } from '../types'; import { Palette } from '../../../Theme'; -import useTranslations from '../../../translations'; +import { useTranslation } from 'react-i18next'; import { Page } from '../../../components/Page'; import SpeedDial from './SpeedDial'; import { useSummary } from './useSummary'; import { ColumnStats, ColumnStatsItem, ActionItem } from './types'; -import useTranslation from '../../../translations'; import useCrypto from '../../../crypto/useCrypto'; import isSearchMatch from '../is-search-match'; import { Box } from '@mui/system'; @@ -36,7 +35,7 @@ interface SectionProps { } const Section = ({ stats, search }: SectionProps) => { - const { SummaryBoard: translations } = useTranslation(); + const { t } = useTranslation(); return ( @@ -53,7 +52,7 @@ const Section = ({ stats, search }: SectionProps) => { {stats.items.length ? ( ) : ( - {translations.noPosts} + {t('SummaryBoard.noPosts')} )} @@ -194,9 +193,7 @@ interface ActionsListProps { const ActionsList = ({ actions }: ActionsListProps) => { const theme = useTheme(); - const { - Actions: { summaryTitle }, - } = useTranslations(); + const { t } = useTranslation(); const { decrypt } = useCrypto(); return ( { - {summaryTitle} + {t('Actions.summaryTitle')} } style={{ diff --git a/frontend/src/views/game/summary/useMarkdown.ts b/frontend/src/views/game/summary/useMarkdown.ts index 24e507157..e90ad7667 100644 --- a/frontend/src/views/game/summary/useMarkdown.ts +++ b/frontend/src/views/game/summary/useMarkdown.ts @@ -4,7 +4,7 @@ import sortedUniq from 'lodash/sortedUniq'; import sortBy from 'lodash/sortBy'; import { format } from 'date-fns'; import useColumns from '../useColumns'; -import useTranslations from '../../../translations'; +import { useTranslation } from 'react-i18next'; import { useSummary } from './useSummary'; import { ColumnStatsItem, ActionItem } from './types'; import useSession from '../useSession'; @@ -12,7 +12,7 @@ import useSession from '../useSession'; export default function useMarkdown() { const { session } = useSession(); const columns = useColumns(); - const translations = useTranslations(); + const { t } = useTranslation(); const stats = useSummary(columns); const result = useMemo(() => { @@ -37,7 +37,7 @@ export default function useMarkdown() { let md = ` # Retrospected Session -## ${session.name || translations.SessionName.defaultSessionName} +## ${session.name || t('SessionName.defaultSessionName')} ### Session details: @@ -68,7 +68,7 @@ ${[...col.items].map((i) => toItem(i, 0)).join('\n')} }); return md; - }, [session, translations.SessionName.defaultSessionName, stats]); + }, [session, t, stats]); return result; } diff --git a/frontend/src/views/game/useColumns.ts b/frontend/src/views/game/useColumns.ts index ed6b6759e..adcd86b49 100644 --- a/frontend/src/views/game/useColumns.ts +++ b/frontend/src/views/game/useColumns.ts @@ -1,6 +1,6 @@ import { useMemo } from 'react'; import sortBy from 'lodash/sortBy'; -import useTranslations from '../../translations'; +import { useTranslation } from 'react-i18next'; import { ColumnContent } from './types'; import { extrapolate } from '../../state/columns'; import { ColumnDefinition, Post, PostGroup } from 'common'; @@ -11,7 +11,7 @@ const emptyGroups: PostGroup[] = []; const emptyCols: ColumnDefinition[] = []; export default function useColumns() { - const translations = useTranslations(); + const { t } = useTranslation(); const { session } = useSession(); const posts = session ? session.posts : emptyPosts; const groups = session ? session.groups : emptyGroups; @@ -20,7 +20,7 @@ export default function useColumns() { const columns: ColumnContent[] = useMemo( () => cols - .map((col) => extrapolate(col, translations)) + .map((col) => extrapolate(col, t)) .map( (col, index) => ({ @@ -41,7 +41,7 @@ export default function useColumns() { ...col, } as ColumnContent) ), - [posts, groups, cols, translations] + [posts, groups, cols, t] ); return columns; } diff --git a/frontend/src/views/game/useGame.ts b/frontend/src/views/game/useGame.ts index b5ab91470..bebfc15ee 100644 --- a/frontend/src/views/game/useGame.ts +++ b/frontend/src/views/game/useGame.ts @@ -36,13 +36,13 @@ import { getRemovedParticipants, joinNames, } from './participants-notifiers'; -import useTranslation from '../../translations/useTranslations'; import { omit } from 'lodash'; import { AckItem } from './types'; import useMutableRead from '../../hooks/useMutableRead'; import useParticipants from './useParticipants'; import useUnauthorised from './useUnauthorised'; import useSession from './useSession'; +import { useTranslation } from 'react-i18next'; export type Status = /** @@ -98,7 +98,7 @@ const useGame = (sessionId: string) => { const { user, initialised: userInitialised } = useUserMetadata(); const userId = !user ? user : user.id; const { enqueueSnackbar } = useSnackbar(); - const translations = useTranslation(); + const { t } = useTranslation(); const [status, setStatus] = useState( user === undefined ? 'disconnected' : 'not-connected' ); @@ -366,7 +366,7 @@ const useGame = (sessionId: string) => { if (debug) { console.log('Receive Error: ', payload); } - enqueueSnackbar(translations.PostBoard.error!(payload.type), { + enqueueSnackbar(t(`PostBoard.error_${payload.type}` as any), { variant: 'error', }); if (payload.type !== 'cannot_get_session') { @@ -391,7 +391,7 @@ const useGame = (sessionId: string) => { } userReady(readyUserId, ready); if (userId !== readyUserId && ready) { - enqueueSnackbar(translations.PostBoard.userIsReady!(name), { + enqueueSnackbar(t('PostBoard.userIsReady', { user: name }), { variant: 'success', }); } @@ -401,7 +401,7 @@ const useGame = (sessionId: string) => { socket, status, sessionId, - translations, + t, statusValue, resetSession, receivePost, @@ -434,7 +434,7 @@ const useGame = (sessionId: string) => { participants ); if (added.length) { - enqueueSnackbar(translations.Clients.joined!(joinNames(added)), { + enqueueSnackbar(t('Clients.joined', { users: joinNames(added) }), { variant: 'success', }); } @@ -444,19 +444,13 @@ const useGame = (sessionId: string) => { participants ); if (removed.length) { - enqueueSnackbar(translations.Clients.left!(joinNames(removed)), { + enqueueSnackbar(t('Clients.left', { users: joinNames(removed) }), { variant: 'info', }); } setPreviousParticipants(participants); } - }, [ - participants, - previousParticipans, - enqueueSnackbar, - userId, - translations, - ]); + }, [participants, previousParticipans, enqueueSnackbar, userId, t]); // Callbacks const onAddPost = useCallback( diff --git a/frontend/src/views/home/CreateSession.tsx b/frontend/src/views/home/CreateSession.tsx index f60064fd8..6aa4f638b 100644 --- a/frontend/src/views/home/CreateSession.tsx +++ b/frontend/src/views/home/CreateSession.tsx @@ -2,7 +2,7 @@ import { useCallback, useMemo } from 'react'; import { SessionOptions, ColumnDefinition, defaultOptions } from 'common'; import { buildDefaults, toColumnDefinitions } from '../../state/columns'; import { ColumnSettings } from '../../state/types'; -import useTranslations from '../../translations'; +import { useTranslation } from 'react-i18next'; import { trackEvent } from './../../track'; import SessionEditor from '../session-editor/SessionEditor'; @@ -21,10 +21,10 @@ const CreateSessionModal = ({ onClose, onLaunch, }: CreateSessionModalProps) => { - const translations = useTranslations(); + const { t } = useTranslation(); const defaultDefinitions = useMemo(() => { - return buildDefaults('default', translations); - }, [translations]); + return buildDefaults('default', t); + }, [t]); const handleChange = useCallback( ( diff --git a/frontend/src/views/home/TrialPrompt.tsx b/frontend/src/views/home/TrialPrompt.tsx index c22410a9d..2ecb7d65e 100644 --- a/frontend/src/views/home/TrialPrompt.tsx +++ b/frontend/src/views/home/TrialPrompt.tsx @@ -4,7 +4,7 @@ import { Link } from 'react-router-dom'; import useIsTrial from '../../auth/useIsTrial'; import useUser from '../../auth/useUser'; import useFormatDate from '../../hooks/useFormatDate'; -import useTranslations from '../../translations'; +import { useTranslation } from 'react-i18next'; import useQuota from '../../hooks/useQuota'; import Button from '@mui/material/Button'; import ProButton from '../../components/ProButton'; @@ -13,7 +13,7 @@ export default function TrialPrompt() { const user = useUser(); const isInTrial = useIsTrial(); const formatDistanceToNow = useFormatDate(); - const { TrialPrompt: translations } = useTranslations(); + const { t } = useTranslation(); const { quota } = useQuota(); const quotaLeft = !!quota ? quota.quota - quota.posts : null; const overQuota = !!quota && quota.posts >= quota.quota; @@ -29,13 +29,13 @@ export default function TrialPrompt() { return ( - {translations.onTrialTitle} - {translations.remainingTrialSentence!( - formatDistanceToNow(new Date(user.trial)) - )} + {t('TrialPrompt.onTrialTitle')} + {t('TrialPrompt.remainingTrialSentence', { + remaining: formatDistanceToNow(new Date(user.trial)), + })}   - {translations.subscribeNow} + {t('TrialPrompt.subscribeNow')} ); @@ -45,17 +45,17 @@ export default function TrialPrompt() { <> {user.trial && !isInTrial ? ( - {translations.trialEndedTitle} - {translations.trialEndedSentence}  + {t('TrialPrompt.trialEndedTitle')} + {t('TrialPrompt.trialEndedSentence')}  - {translations.subscribeNow} + {t('TrialPrompt.subscribeNow')} ) : null} {overQuota ? ( - {translations.allowanceReachedTitle} - {translations.allowanceReachedDescription} + {t('TrialPrompt.allowanceReachedTitle')} + {t('TrialPrompt.allowanceReachedDescription')} ) : null} {nearQuota ? ( - {translations.nearEndAllowanceTitle} - {translations.nearEndAllowanceDescription!(quotaLeft)} + {t('TrialPrompt.nearEndAllowanceTitle')} + {t('TrialPrompt.nearEndAllowanceDescription', { quota: quotaLeft })} diff --git a/frontend/src/views/home/game-item/EncryptedLock.tsx b/frontend/src/views/home/game-item/EncryptedLock.tsx index 7cb5fa598..13d9849b6 100644 --- a/frontend/src/views/home/game-item/EncryptedLock.tsx +++ b/frontend/src/views/home/game-item/EncryptedLock.tsx @@ -4,8 +4,8 @@ import { Lock, LockOpenOutlined, LockOutlined } from '@mui/icons-material'; import { SessionMetadata } from 'common'; import { CHECK_PREFIX, decrypt } from '../../../crypto/crypto'; import { useEncryptionKey } from '../../../crypto/useEncryptionKey'; -import useTranslation from '../../../translations/useTranslations'; import ProButton from '../../../components/ProButton'; +import { useTranslation } from 'react-i18next'; interface EncryptedLockProps { session: SessionMetadata; @@ -13,13 +13,13 @@ interface EncryptedLockProps { function EncryptedLock({ session }: EncryptedLockProps) { const [key] = useEncryptionKey(session.id); - const { Encryption: translations } = useTranslation(); + const { t } = useTranslation(); if (!session.encrypted) { return (
- +
@@ -29,7 +29,7 @@ function EncryptedLock({ session }: EncryptedLockProps) { if (!key) { return ( - + ); @@ -37,14 +37,14 @@ function EncryptedLock({ session }: EncryptedLockProps) { if (decrypt(session.encrypted, key) !== CHECK_PREFIX) { return ( - + ); } return ( - + ); diff --git a/frontend/src/views/home/game-item/PreviousGameItem.tsx b/frontend/src/views/home/game-item/PreviousGameItem.tsx index 2b6e977ca..523de6cbb 100644 --- a/frontend/src/views/home/game-item/PreviousGameItem.tsx +++ b/frontend/src/views/home/game-item/PreviousGameItem.tsx @@ -16,7 +16,7 @@ import CustomAvatar from '../../../components/Avatar'; import ItemStat from '../ItemStat'; import styled from '@emotion/styled'; import useOnHover from '../../../hooks/useOnHover'; -import useTranslations from '../../../translations'; +import { useTranslation } from 'react-i18next'; import { DeleteForever } from '@mui/icons-material'; import { useEncryptionKey } from '../../../crypto/useEncryptionKey'; import useFormatDate from '../../../hooks/useFormatDate'; @@ -35,11 +35,7 @@ const PreviousGameItem = ({ onClick, onDelete, }: PreviousGameItemProps) => { - const { - PreviousGame: translations, - SessionName: { defaultSessionName }, - DeleteSession, - } = useTranslations(); + const { t } = useTranslation(); const [encryptionKey] = useEncryptionKey(session.id); const formatDistanceToNow = useFormatDate(); const [hover, hoverRef] = useOnHover(); @@ -62,6 +58,7 @@ const PreviousGameItem = ({ setDeleteDialogOpen(false); }, []); const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); + return ( <> @@ -87,39 +84,47 @@ const PreviousGameItem = ({ - {decrypt(session.name, encryptionKey) || defaultSessionName}  + {decrypt(session.name, encryptionKey) || + t('SessionName.defaultSessionName')} +   - {translations.createdBy} {session.createdBy.name} + {t('PreviousGame.createdBy')} {session.createdBy.name} {session.participants.map((user) => { return ; @@ -133,23 +138,27 @@ const PreviousGameItem = ({ open={deleteDialogOpen} > - {DeleteSession.header!( - decrypt(session.name, encryptionKey) || defaultSessionName! - )} + {t('DeleteSession.header', { + name: + decrypt(session.name, encryptionKey) || + t('SessionName.defaultSessionName'), + })} - {DeleteSession.firstLine} - {DeleteSession.secondLine} + {t('DeleteSession.firstLine')} + {t('DeleteSession.secondLine')} - +
diff --git a/frontend/src/views/home/game-item/PrivateSessionIcon.tsx b/frontend/src/views/home/game-item/PrivateSessionIcon.tsx index 4bb07673b..73a116ddc 100644 --- a/frontend/src/views/home/game-item/PrivateSessionIcon.tsx +++ b/frontend/src/views/home/game-item/PrivateSessionIcon.tsx @@ -2,21 +2,21 @@ import { colors } from '@mui/material'; import Tooltip from '@mui/material/Tooltip'; import { VerifiedUser, VerifiedUserOutlined } from '@mui/icons-material'; import { SessionMetadata } from 'common'; -import useTranslation from '../../../translations/useTranslations'; import ProButton from '../../../components/ProButton'; +import { useTranslation } from 'react-i18next'; interface PrivateSessionIconProps { session: SessionMetadata; } function PrivateSessionIcon({ session }: PrivateSessionIconProps) { - const { Private: translations } = useTranslation(); + const { t } = useTranslation(); if (!session.locked) { return (
- +
@@ -26,13 +26,13 @@ function PrivateSessionIcon({ session }: PrivateSessionIconProps) { if (!session.lockedForUser) { return ( - + ); } return ( - + ); diff --git a/frontend/src/views/layout/Invite.tsx b/frontend/src/views/layout/Invite.tsx index b2b92019e..8df2d02c7 100644 --- a/frontend/src/views/layout/Invite.tsx +++ b/frontend/src/views/layout/Invite.tsx @@ -8,12 +8,12 @@ import DialogActions from '@mui/material/DialogActions'; import DialogContent from '@mui/material/DialogContent'; import DialogContentText from '@mui/material/DialogContentText'; import Clipboard from 'react-copy-to-clipboard'; -import useTranslations from '../../translations'; +import { useTranslation } from 'react-i18next'; export default function Invite() { const [isOpen, open] = useState(false); const toggle = useCallback(() => open(!isOpen), [open, isOpen]); - const translations = useTranslations(); + const { t } = useTranslation(); const url = window.location.href; return ( <> @@ -21,11 +21,9 @@ export default function Invite() { - {translations.Invite.dialog.title} + {t('Invite.dialog.title')} - - {translations.Invite.dialog.text}: - + {t('Invite.dialog.text')}:    - {translations.Invite.dialog.copyButton} + {t('Invite.dialog.copyButton')} - + diff --git a/frontend/src/views/panel/ParticipantsList.tsx b/frontend/src/views/panel/ParticipantsList.tsx index 5d553c60f..8556c78f8 100644 --- a/frontend/src/views/panel/ParticipantsList.tsx +++ b/frontend/src/views/panel/ParticipantsList.tsx @@ -4,19 +4,19 @@ import ListItem from '@mui/material/ListItem'; import ListItemText from '@mui/material/ListItemText'; import ListSubheader from '@mui/material/ListSubheader'; import Avatar from '../../components/Avatar'; -import useTranslations from '../../translations'; +import { useTranslation } from 'react-i18next'; import { colors } from '@mui/material'; import useParticipants from '../game/useParticipants'; function ParticipantsList() { - const translations = useTranslations(); + const { t } = useTranslation(); const { participants } = useParticipants(); return ( <> {translations.Clients.header}} + subheader={{t('Clients.header')}} > {participants.map((player, index) => ( diff --git a/frontend/src/views/session-editor/SessionEditor.tsx b/frontend/src/views/session-editor/SessionEditor.tsx index 139ce9819..3d709e450 100644 --- a/frontend/src/views/session-editor/SessionEditor.tsx +++ b/frontend/src/views/session-editor/SessionEditor.tsx @@ -10,7 +10,7 @@ import Button from '@mui/material/Button'; import AppBar from '@mui/material/AppBar'; import Tabs from '@mui/material/Tabs'; import Tab from '@mui/material/Tab'; -import useTranslations from '../../translations'; +import { useTranslation } from 'react-i18next'; import useToggle from '../../hooks/useToggle'; import { ColumnSettings } from '../../state/types'; import TemplateSection from './sections/template/TemplateSection'; @@ -39,8 +39,7 @@ function SessionEditor({ onChange, onClose, }: SessionEditorProps) { - const translations = useTranslations(); - const { Customize, Generic } = translations; + const { t } = useTranslation(); const fullScreen = useMediaQuery('(max-width:600px)'); const [isDefaultTemplate, toggleIsDefaultTemplate] = useToggle(false); const [definitions, setDefinitions] = useState(columns); @@ -48,29 +47,20 @@ function SessionEditor({ const [currentTab, setCurrentTab] = useState('template'); useEffect(() => { - const extrapolatedColumns = columns.map((c) => - extrapolate(c, translations) - ); + const extrapolatedColumns = columns.map((c) => extrapolate(c, t)); setDefinitions(extrapolatedColumns); - }, [columns, translations]); + }, [columns, t]); useEffect(() => { setOptions(incomingOptions); }, [incomingOptions]); const handleCreate = useCallback(() => { - const definitionsToPersist = hasChanged(columns, definitions, translations) + const definitionsToPersist = hasChanged(columns, definitions, t) ? definitions : columns; onChange(options, definitionsToPersist, isDefaultTemplate); - }, [ - onChange, - options, - definitions, - isDefaultTemplate, - columns, - translations, - ]); + }, [onChange, options, definitions, isDefaultTemplate, columns, t]); const handleTab = useCallback((_: React.ChangeEvent<{}>, value: string) => { setCurrentTab(value); @@ -94,9 +84,9 @@ function SessionEditor({ scrollButtons="auto" aria-label="scrollable auto tabs example" > - - - + + + @@ -118,13 +108,13 @@ function SessionEditor({ onChange={toggleIsDefaultTemplate} /> } - label={Customize.makeDefaultTemplate!} + label={t('Customize.makeDefaultTemplate')!} /> diff --git a/frontend/src/views/session-editor/sections/posts/PostsSection.tsx b/frontend/src/views/session-editor/sections/posts/PostsSection.tsx index e53c18b91..d07fc8e42 100644 --- a/frontend/src/views/session-editor/sections/posts/PostsSection.tsx +++ b/frontend/src/views/session-editor/sections/posts/PostsSection.tsx @@ -2,7 +2,7 @@ import { useCallback } from 'react'; import { SessionOptions } from 'common'; import SettingCategory from '../SettingCategory'; import OptionItem from '../OptionItem'; -import useTranslations from '../../../../translations'; +import { useTranslation } from 'react-i18next'; import BooleanOption from '../BooleanOption'; import MaxPostsSlider from './MaxPostsSlider'; @@ -12,8 +12,7 @@ interface PostsSectionProps { } function PostsSection({ options, onChange }: PostsSectionProps) { - const translations = useTranslations(); - const { Customize } = translations; + const { t } = useTranslation(); const setAllowAction = useCallback( (value: boolean) => { @@ -97,28 +96,31 @@ function PostsSection({ options, onChange }: PostsSectionProps) { return ( - + diff --git a/frontend/src/views/session-editor/sections/template/TemplateEditor.tsx b/frontend/src/views/session-editor/sections/template/TemplateEditor.tsx index 19558093d..b1971a41e 100644 --- a/frontend/src/views/session-editor/sections/template/TemplateEditor.tsx +++ b/frontend/src/views/session-editor/sections/template/TemplateEditor.tsx @@ -1,11 +1,11 @@ import { useCallback } from 'react'; import { ColumnSettings } from '../../../../state/types'; import ColumnEditor from './ColumnEditor'; -import useTranslation from '../../../../translations/useTranslations'; import { getTemplateColumnByType } from '../../../../state/columns'; import IconButton from '@mui/material/IconButton'; import { trackEvent } from '../../../../track'; import { Add } from '@mui/icons-material'; +import { useTranslation } from 'react-i18next'; const MAX_NUMBER_OF_COLUMNS = 5; @@ -15,7 +15,7 @@ interface TemplateEditorProps { } function TemplateEditor({ columns, onChange }: TemplateEditorProps) { - const translations = useTranslation(); + const { t } = useTranslation(); const handleColumnChange = useCallback( (value: ColumnSettings, index: number) => { onChange(Object.assign([], columns, { [index]: value })); @@ -24,10 +24,10 @@ function TemplateEditor({ columns, onChange }: TemplateEditorProps) { [onChange, columns] ); const handleAddColumn = useCallback(() => { - const custom = getTemplateColumnByType(translations)('custom'); + const custom = getTemplateColumnByType(t)('custom'); onChange([...columns, custom]); trackEvent('custom-modal/column/add'); - }, [onChange, columns, translations]); + }, [onChange, columns, t]); const handleRemoveColumn = useCallback( (column: ColumnSettings) => { onChange(columns.filter((c) => c !== column)); @@ -35,22 +35,24 @@ function TemplateEditor({ columns, onChange }: TemplateEditorProps) { }, [onChange, columns] ); - return <> - {columns.map((def, index) => ( - 1} - onChange={(value) => handleColumnChange(value, index)} - onRemove={handleRemoveColumn} - /> - ))} - {columns.length < MAX_NUMBER_OF_COLUMNS ? ( - - - - ) : null} - ; + return ( + <> + {columns.map((def, index) => ( + 1} + onChange={(value) => handleColumnChange(value, index)} + onRemove={handleRemoveColumn} + /> + ))} + {columns.length < MAX_NUMBER_OF_COLUMNS ? ( + + + + ) : null} + + ); } export default TemplateEditor; diff --git a/frontend/src/views/session-editor/sections/template/TemplatePicker.tsx b/frontend/src/views/session-editor/sections/template/TemplatePicker.tsx index 0fa02c4ff..141769771 100644 --- a/frontend/src/views/session-editor/sections/template/TemplatePicker.tsx +++ b/frontend/src/views/session-editor/sections/template/TemplatePicker.tsx @@ -1,7 +1,7 @@ import { useCallback, useState } from 'react'; import { Template } from '../../../../state/types'; import { getAllTemplates } from '../../../../state/templates'; -import useTranslations from '../../../../translations'; +import { useTranslation } from 'react-i18next'; import Select from '@mui/material/Select'; import MenuItem from '@mui/material/MenuItem'; import { SelectChangeEvent } from '@mui/material'; @@ -11,9 +11,9 @@ interface TemplatePickerProps { } const TemplatePicker = ({ onSelect }: TemplatePickerProps) => { - const translations = useTranslations(); + const { t } = useTranslation(); const [template, setTemplate] = useState