diff --git a/fe/package-lock.json b/fe/package-lock.json index a49cb17..23a1c65 100644 --- a/fe/package-lock.json +++ b/fe/package-lock.json @@ -23,7 +23,7 @@ "workbox-background-sync": "^7.3.0" }, "devDependencies": { - "@intlify/unplugin-vue-i18n": "^6.0.8", + "@intlify/unplugin-vue-i18n": "^4.0.0", "@playwright/test": "^1.51.1", "@storybook/addon-docs": "^9.0.2", "@storybook/addon-onboarding": "^9.0.2", @@ -2558,14 +2558,13 @@ } }, "node_modules/@intlify/bundle-utils": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/@intlify/bundle-utils/-/bundle-utils-10.0.1.tgz", - "integrity": "sha512-WkaXfSevtpgtUR4t8K2M6lbR7g03mtOxFeh+vXp5KExvPqS12ppaRj1QxzwRuRI5VUto54A22BjKoBMLyHILWQ==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@intlify/bundle-utils/-/bundle-utils-8.0.0.tgz", + "integrity": "sha512-1B++zykRnMwQ+20SpsZI1JCnV/YJt9Oq7AGlEurzkWJOFtFAVqaGc/oV36PBRYeiKnTbY9VYfjBimr2Vt42wLQ==", "dev": true, - "license": "MIT", "dependencies": { - "@intlify/message-compiler": "^11.1.2", - "@intlify/shared": "^11.1.2", + "@intlify/message-compiler": "^9.4.0", + "@intlify/shared": "^9.4.0", "acorn": "^8.8.2", "escodegen": "^2.1.0", "estree-walker": "^2.0.2", @@ -2575,7 +2574,7 @@ "yaml-eslint-parser": "^1.2.2" }, "engines": { - "node": ">= 18" + "node": ">= 14.16" }, "peerDependenciesMeta": { "petite-vue-i18n": { @@ -2587,13 +2586,12 @@ } }, "node_modules/@intlify/bundle-utils/node_modules/@intlify/message-compiler": { - "version": "11.1.3", - "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-11.1.3.tgz", - "integrity": "sha512-7rbqqpo2f5+tIcwZTAG/Ooy9C8NDVwfDkvSeDPWUPQW+Dyzfw2o9H103N5lKBxO7wxX9dgCDjQ8Umz73uYw3hw==", + "version": "9.14.4", + "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.14.4.tgz", + "integrity": "sha512-vcyCLiVRN628U38c3PbahrhbbXrckrM9zpy0KZVlDk2Z0OnGwv8uQNNXP3twwGtfLsCf4gu3ci6FMIZnPaqZsw==", "dev": true, - "license": "MIT", "dependencies": { - "@intlify/shared": "11.1.3", + "@intlify/shared": "9.14.4", "source-map-js": "^1.0.2" }, "engines": { @@ -2604,11 +2602,10 @@ } }, "node_modules/@intlify/bundle-utils/node_modules/@intlify/shared": { - "version": "11.1.3", - "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-11.1.3.tgz", - "integrity": "sha512-pTFBgqa/99JRA2H1qfyqv97MKWJrYngXBA/I0elZcYxvJgcCw3mApAoPW3mJ7vx3j+Ti0FyKUFZ4hWxdjKaxvA==", + "version": "9.14.4", + "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.14.4.tgz", + "integrity": "sha512-P9zv6i1WvMc9qDBWvIgKkymjY2ptIiQ065PjDv7z7fDqH3J/HBRBN5IoiR46r/ujRcU7hCuSIZWvCAFCyuOYZA==", "dev": true, - "license": "MIT", "engines": { "node": ">= 16" }, @@ -2661,19 +2658,15 @@ } }, "node_modules/@intlify/unplugin-vue-i18n": { - "version": "6.0.8", - "resolved": "https://registry.npmjs.org/@intlify/unplugin-vue-i18n/-/unplugin-vue-i18n-6.0.8.tgz", - "integrity": "sha512-Vvm3KhjE6TIBVUQAk37rBiaYy2M5OcWH0ZcI1XKEsOTeN1o0bErk+zeuXmcrcMc/73YggfI8RoxOUz9EB/69JQ==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@intlify/unplugin-vue-i18n/-/unplugin-vue-i18n-4.0.0.tgz", + "integrity": "sha512-q2Mhqa/mLi0tulfLFO4fMXXvEbkSZpI5yGhNNsLTNJJ41icEGUuyDe+j5zRZIKSkOJRgX6YbCyibTDJdRsukmw==", "dev": true, - "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@intlify/bundle-utils": "^10.0.1", - "@intlify/shared": "^11.1.2", - "@intlify/vue-i18n-extensions": "^8.0.0", + "@intlify/bundle-utils": "^8.0.0", + "@intlify/shared": "^9.4.0", "@rollup/pluginutils": "^5.1.0", - "@typescript-eslint/scope-manager": "^8.13.0", - "@typescript-eslint/typescript-estree": "^8.13.0", + "@vue/compiler-sfc": "^3.2.47", "debug": "^4.3.3", "fast-glob": "^3.2.12", "js-yaml": "^4.1.0", @@ -2681,16 +2674,15 @@ "pathe": "^1.0.0", "picocolors": "^1.0.0", "source-map-js": "^1.0.2", - "unplugin": "^1.1.0", - "vue": "^3.4" + "unplugin": "^1.1.0" }, "engines": { - "node": ">= 18" + "node": ">= 14.16" }, "peerDependencies": { "petite-vue-i18n": "*", - "vue": "^3.2.25", - "vue-i18n": "*" + "vue-i18n": "*", + "vue-i18n-bridge": "*" }, "peerDependenciesMeta": { "petite-vue-i18n": { @@ -2698,15 +2690,17 @@ }, "vue-i18n": { "optional": true + }, + "vue-i18n-bridge": { + "optional": true } } }, "node_modules/@intlify/unplugin-vue-i18n/node_modules/@intlify/shared": { - "version": "11.1.3", - "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-11.1.3.tgz", - "integrity": "sha512-pTFBgqa/99JRA2H1qfyqv97MKWJrYngXBA/I0elZcYxvJgcCw3mApAoPW3mJ7vx3j+Ti0FyKUFZ4hWxdjKaxvA==", + "version": "9.14.4", + "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-9.14.4.tgz", + "integrity": "sha512-P9zv6i1WvMc9qDBWvIgKkymjY2ptIiQ065PjDv7z7fDqH3J/HBRBN5IoiR46r/ujRcU7hCuSIZWvCAFCyuOYZA==", "dev": true, - "license": "MIT", "engines": { "node": ">= 16" }, @@ -2744,117 +2738,6 @@ "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", "license": "MIT" }, - "node_modules/@intlify/vue-i18n-extensions": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@intlify/vue-i18n-extensions/-/vue-i18n-extensions-8.0.0.tgz", - "integrity": "sha512-w0+70CvTmuqbskWfzeYhn0IXxllr6mU+IeM2MU0M+j9OW64jkrvqY+pYFWrUnIIC9bEdij3NICruicwd5EgUuQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.24.6", - "@intlify/shared": "^10.0.0", - "@vue/compiler-dom": "^3.2.45", - "vue-i18n": "^10.0.0" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "@intlify/shared": "^9.0.0 || ^10.0.0 || ^11.0.0", - "@vue/compiler-dom": "^3.0.0", - "vue": "^3.0.0", - "vue-i18n": "^9.0.0 || ^10.0.0 || ^11.0.0" - }, - "peerDependenciesMeta": { - "@intlify/shared": { - "optional": true - }, - "@vue/compiler-dom": { - "optional": true - }, - "vue": { - "optional": true - }, - "vue-i18n": { - "optional": true - } - } - }, - "node_modules/@intlify/vue-i18n-extensions/node_modules/@intlify/core-base": { - "version": "10.0.7", - "resolved": "https://registry.npmjs.org/@intlify/core-base/-/core-base-10.0.7.tgz", - "integrity": "sha512-mE71aUH5baH0me8duB4FY5qevUJizypHsYw3eCvmOx07QvmKppgOONx3dYINxuA89Z2qkAGb/K6Nrpi7aAMwew==", - "dev": true, - "license": "MIT", - "dependencies": { - "@intlify/message-compiler": "10.0.7", - "@intlify/shared": "10.0.7" - }, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/kazupon" - } - }, - "node_modules/@intlify/vue-i18n-extensions/node_modules/@intlify/message-compiler": { - "version": "10.0.7", - "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-10.0.7.tgz", - "integrity": "sha512-nrC4cDL/UHZSUqd8sRbVz+DPukzZ8NnG5OK+EB/nlxsH35deyzyVkXP/QuR8mFZrISJ+4hCd6VtCQCcT+RO+5g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@intlify/shared": "10.0.7", - "source-map-js": "^1.0.2" - }, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/kazupon" - } - }, - "node_modules/@intlify/vue-i18n-extensions/node_modules/@intlify/shared": { - "version": "10.0.7", - "resolved": "https://registry.npmjs.org/@intlify/shared/-/shared-10.0.7.tgz", - "integrity": "sha512-oeoq0L5+5P4ShXa6jBQcx+BT+USe3MjX0xJexZO1y7rfDJdwZ9+QP3jO4tcS1nxhBYYdjvFTqe4bmnLijV0GxQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/kazupon" - } - }, - "node_modules/@intlify/vue-i18n-extensions/node_modules/@vue/devtools-api": { - "version": "6.6.4", - "resolved": "https://registry.npmjs.org/@vue/devtools-api/-/devtools-api-6.6.4.tgz", - "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", - "dev": true, - "license": "MIT" - }, - "node_modules/@intlify/vue-i18n-extensions/node_modules/vue-i18n": { - "version": "10.0.7", - "resolved": "https://registry.npmjs.org/vue-i18n/-/vue-i18n-10.0.7.tgz", - "integrity": "sha512-bKsk0PYwP9gdYF4nqSAT0kDpnLu1gZzlxFl885VH4mHVhEnqP16+/mAU05r1U6NIrc0fGDWP89tZ8GzeJZpe+w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@intlify/core-base": "10.0.7", - "@intlify/shared": "10.0.7", - "@vue/devtools-api": "^6.5.0" - }, - "engines": { - "node": ">= 16" - }, - "funding": { - "url": "https://github.com/sponsors/kazupon" - }, - "peerDependencies": { - "vue": "^3.0.0" - } - }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", @@ -6040,8 +5923,7 @@ "version": "0.1.8", "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/config-chain": { "version": "1.1.13", @@ -6848,7 +6730,6 @@ "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "esprima": "^4.0.1", "estraverse": "^5.2.0", @@ -9092,7 +8973,6 @@ "resolved": "https://registry.npmjs.org/jsonc-eslint-parser/-/jsonc-eslint-parser-2.4.0.tgz", "integrity": "sha512-WYDyuc/uFcGp6YtM2H0uKmUwieOuzeE/5YocFJLnLfclZ4inf3mRn8ZVy1s7Hxji7Jxm6Ss8gqpexD/GlKoGgg==", "dev": true, - "license": "MIT", "dependencies": { "acorn": "^8.5.0", "eslint-visitor-keys": "^3.0.0", @@ -9111,7 +8991,6 @@ "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", "dev": true, - "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", @@ -9444,7 +9323,6 @@ "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.4.tgz", "integrity": "sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==", "dev": true, - "license": "MIT", "dependencies": { "acorn": "^8.14.0", "pathe": "^2.0.1", @@ -10118,7 +9996,6 @@ "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", "dev": true, - "license": "MIT", "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", @@ -12273,8 +12150,7 @@ "version": "1.6.1", "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.1.tgz", "integrity": "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==", - "dev": true, - "license": "MIT" + "dev": true }, "node_modules/unbox-primitive": { "version": "1.1.0", @@ -13868,7 +13744,6 @@ "resolved": "https://registry.npmjs.org/yaml-eslint-parser/-/yaml-eslint-parser-1.3.0.tgz", "integrity": "sha512-E/+VitOorXSLiAqtTd7Yqax0/pAS3xaYMP+AUUJGOK1OZG3rhcj9fcJOM5HJ2VrP1FrStVCWr1muTfQCdj4tAA==", "dev": true, - "license": "MIT", "dependencies": { "eslint-visitor-keys": "^3.0.0", "yaml": "^2.0.0" diff --git a/fe/package.json b/fe/package.json index 6f3f247..1a6b9d6 100644 --- a/fe/package.json +++ b/fe/package.json @@ -34,7 +34,7 @@ "workbox-background-sync": "^7.3.0" }, "devDependencies": { - "@intlify/unplugin-vue-i18n": "^6.0.8", + "@intlify/unplugin-vue-i18n": "^4.0.0", "@playwright/test": "^1.51.1", "@storybook/addon-docs": "^9.0.2", "@storybook/addon-onboarding": "^9.0.2", diff --git a/fe/src/i18n/de.json b/fe/src/i18n/de.json new file mode 100644 index 0000000..838bc94 --- /dev/null +++ b/fe/src/i18n/de.json @@ -0,0 +1,274 @@ +{ + "message": { + "hello": "Hallo" + }, + "loginPage": { + "emailLabel": "DE: Email", + "passwordLabel": "DE: Password", + "togglePasswordVisibilityLabel": "DE: Toggle password visibility", + "loginButton": "DE: Login", + "signupLink": "DE: Don't have an account? Sign up", + "errors": { + "emailRequired": "DE: Email is required", + "emailInvalid": "DE: Invalid email format", + "passwordRequired": "DE: Password is required", + "loginFailed": "DE: Login failed. Please check your credentials." + }, + "notifications": { + "loginSuccess": "DE: Login successful" + } + }, + "listsPage": { + "retryButton": "DE: Retry", + "emptyState": { + "noListsForGroup": "DE: No lists found for this group.", + "noListsYet": "DE: You have no lists yet.", + "personalGlobalInfo": "DE: Create a personal list or join a group to see shared lists.", + "groupSpecificInfo": "DE: This group doesn't have any lists yet." + }, + "createNewListButton": "DE: Create New List", + "loadingLists": "DE: Loading lists...", + "noDescription": "DE: No description", + "addItemPlaceholder": "DE: Add new item...", + "createCard": { + "title": "DE: + Create a new list" + }, + "pageTitle": { + "forGroup": "DE: Lists for {groupName}", + "forGroupId": "DE: Lists for Group {groupId}", + "myLists": "DE: My Lists" + }, + "errors": { + "fetchFailed": "DE: Failed to fetch lists." + } + }, + "groupsPage": { + "retryButton": "DE: Retry", + "emptyState": { + "title": "DE: No Groups Yet!", + "description": "DE: You are not a member of any groups yet. Create one or join using an invite code.", + "createButton": "DE: Create New Group" + }, + "groupCard": { + "newListButton": "DE: List" + }, + "createCard": { + "title": "DE: + Group" + }, + "joinGroup": { + "title": "DE: Join a Group with Invite Code", + "inputLabel": "DE: Enter Invite Code", + "inputPlaceholder": "DE: Enter Invite Code", + "joinButton": "DE: Join" + }, + "createDialog": { + "title": "DE: Create New Group", + "closeButtonLabel": "DE: Close", + "groupNameLabel": "DE: Group Name", + "cancelButton": "DE: Cancel", + "createButton": "DE: Create" + }, + "errors": { + "fetchFailed": "DE: Failed to load groups", + "groupNameRequired": "DE: Group name is required", + "createFailed": "DE: Failed to create group. Please try again.", + "inviteCodeRequired": "DE: Invite code is required", + "joinFailed": "DE: Failed to join group. Please check the invite code and try again." + }, + "notifications": { + "groupCreatedSuccess": "DE: Group '{groupName}' created successfully.", + "joinSuccessNamed": "DE: Successfully joined group '{groupName}'.", + "joinSuccessGeneric": "DE: Successfully joined group.", + "listCreatedSuccess": "DE: List '{listName}' created successfully." + } + }, + "authCallbackPage": { + "redirecting": "DE: Redirecting...", + "errors": { + "authenticationFailed": "DE: Authentication failed" + } + }, + "choresPage": { + "title": "DE: Chores", + "tabs": { + "overdue": "DE: Overdue", + "today": "DE: Today", + "upcoming": "DE: Upcoming", + "allPending": "DE: All Pending", + "completed": "DE: Completed" + }, + "viewToggle": { + "calendarLabel": "DE: Calendar View", + "calendarText": "DE: Calendar", + "listLabel": "DE: List View", + "listText": "DE: List" + }, + "newChoreButtonLabel": "DE: New Chore", + "newChoreButtonText": "DE: New Chore", + "loadingState": { + "loadingChores": "DE: Loading chores..." + }, + "calendar": { + "prevMonthLabel": "DE: Previous month", + "nextMonthLabel": "DE: Next month", + "weekdays": { + "sun": "DE: Sun", + "mon": "DE: Mon", + "tue": "DE: Tue", + "wed": "DE: Wed", + "thu": "DE: Thu", + "fri": "DE: Fri", + "sat": "DE: Sat" + }, + "addChoreToDayLabel": "DE: Add chore to this day", + "emptyState": "DE: No chores to display for this period." + }, + "listView": { + "choreTypePersonal": "DE: Personal", + "choreTypeGroupFallback": "DE: Group", + "completedDatePrefix": "DE: Completed:", + "actions": { + "doneTitle": "DE: Mark as Done", + "doneText": "DE: Done", + "undoTitle": "DE: Mark as Not Done", + "undoText": "DE: Undo", + "editTitle": "DE: Edit", + "editLabel": "DE: Edit chore", + "editText": "DE: Edit", + "deleteTitle": "DE: Delete", + "deleteLabel": "DE: Delete chore", + "deleteText": "DE: Delete" + }, + "emptyState": { + "message": "DE: No chores in this view. Well done!", + "viewAllButton": "DE: View All Pending" + } + }, + "choreModal": { + "editTitle": "DE: Edit Chore", + "newTitle": "DE: New Chore", + "closeButtonLabel": "DE: Close modal", + "nameLabel": "DE: Name", + "namePlaceholder": "DE: Enter chore name", + "typeLabel": "DE: Type", + "typePersonal": "DE: Personal", + "typeGroup": "DE: Group", + "groupLabel": "DE: Group", + "groupSelectDefault": "DE: Select a group", + "descriptionLabel": "DE: Description", + "descriptionPlaceholder": "DE: Add a description (optional)", + "frequencyLabel": "DE: Frequency", + "intervalLabel": "DE: Interval (days)", + "intervalPlaceholder": "DE: e.g. 3", + "dueDateLabel": "DE: Due Date", + "quickDueDateToday": "DE: Today", + "quickDueDateTomorrow": "DE: Tomorrow", + "quickDueDateNextWeek": "DE: Next Week", + "cancelButton": "DE: Cancel", + "saveButton": "DE: Save" + }, + "deleteDialog": { + "title": "DE: Delete Chore", + "confirmationText": "DE: Are you sure you want to delete this chore? This action cannot be undone.", + "deleteButton": "DE: Delete" + }, + "shortcutsModal": { + "title": "DE: Keyboard Shortcuts", + "descNewChore": "DE: New Chore", + "descToggleView": "DE: Toggle View (List/Calendar)", + "descToggleShortcuts": "DE: Show/Hide Shortcuts", + "descCloseModal": "DE: Close any open Modal/Dialog" + }, + "frequencyOptions": { + "oneTime": "DE: One Time", + "daily": "DE: Daily", + "weekly": "DE: Weekly", + "monthly": "DE: Monthly", + "custom": "DE: Custom" + }, + "formatters": { + "noDueDate": "DE: No due date", + "dueToday": "DE: Due Today", + "dueTomorrow": "DE: Due Tomorrow", + "overdueFull": "DE: Overdue: {date}", + "dueFull": "DE: Due {date}", + "invalidDate": "DE: Invalid Date" + }, + "notifications": { + "loadFailed": "DE: Failed to load chores", + "updateSuccess": "DE: Chore '{name}' updated successfully", + "createSuccess": "DE: Chore '{name}' created successfully", + "updateFailed": "DE: Failed to update chore", + "createFailed": "DE: Failed to create chore", + "deleteSuccess": "DE: Chore '{name}' deleted successfully", + "deleteFailed": "DE: Failed to delete chore", + "markedDone": "DE: {name} marked as done.", + "markedNotDone": "DE: {name} marked as not done.", + "statusUpdateFailed": "DE: Failed to update chore status." + }, + "validation": { + "nameRequired": "DE: Chore name is required.", + "groupRequired": "DE: Please select a group for group chores.", + "intervalRequired": "DE: Custom interval must be at least 1 day.", + "dueDateRequired": "DE: Due date is required.", + "invalidDueDate": "DE: Invalid due date format." + }, + "unsavedChangesConfirmation": "DE: You have unsaved changes in the chore form. Are you sure you want to leave?" + }, + "errorNotFoundPage": { + "errorCode": "DE: 404", + "errorMessage": "DE: Oops. Nothing here...", + "goHomeButton": "DE: Go Home" + }, + "groupDetailPage": { + "loadingLabel": "DE: Loading group details...", + "retryButton": "DE: Retry", + "groupNotFound": "DE: Group not found or an error occurred.", + "members": { + "title": "DE: Group Members", + "defaultRole": "DE: Member", + "removeButton": "DE: Remove", + "emptyState": "DE: No members found." + }, + "invites": { + "title": "DE: Invite Members", + "regenerateButton": "DE: Regenerate Invite Code", + "generateButton": "DE: Generate Invite Code", + "activeCodeLabel": "DE: Current Active Invite Code:", + "copyButtonLabel": "DE: Copy invite code", + "copySuccess": "DE: Invite code copied to clipboard!", + "emptyState": "DE: No active invite code. Click the button above to generate one.", + "errors": { + "newDataInvalid": "DE: New invite code data is invalid." + } + }, + "chores": { + "title": "DE: Group Chores", + "manageButton": "DE: Manage Chores", + "duePrefix": "DE: Due:", + "emptyState": "DE: No chores scheduled. Click \"Manage Chores\" to create some!" + }, + "expenses": { + "title": "DE: Group Expenses", + "manageButton": "DE: Manage Expenses", + "emptyState": "DE: No expenses recorded. Click \"Manage Expenses\" to add some!", + "splitTypes": { + "equal": "DE: Equal", + "exactAmounts": "DE: Exact Amounts", + "percentage": "DE: Percentage", + "shares": "DE: Shares", + "itemBased": "DE: Item Based" + } + }, + "notifications": { + "fetchDetailsFailed": "DE: Failed to fetch group details.", + "fetchInviteFailed": "DE: Failed to fetch active invite code.", + "generateInviteSuccess": "DE: New invite code generated successfully!", + "generateInviteError": "DE: Failed to generate invite code.", + "clipboardNotSupported": "DE: Clipboard not supported or no code to copy.", + "copyInviteFailed": "DE: Failed to copy invite code.", + "removeMemberSuccess": "DE: Member removed successfully", + "removeMemberFailed": "DE: Failed to remove member" + } + } +} diff --git a/fe/src/i18n/en-US/index.ts b/fe/src/i18n/en-US/index.ts deleted file mode 100644 index d555d3f..0000000 --- a/fe/src/i18n/en-US/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -// This is just an example, -// so you can safely delete all default props below - -export default { - failed: 'Action failed', - success: 'Action was successful' -}; diff --git a/fe/src/i18n/en.json b/fe/src/i18n/en.json new file mode 100644 index 0000000..133984c --- /dev/null +++ b/fe/src/i18n/en.json @@ -0,0 +1,274 @@ +{ + "message": { + "hello": "Hello" + }, + "loginPage": { + "emailLabel": "Email", + "passwordLabel": "Password", + "togglePasswordVisibilityLabel": "Toggle password visibility", + "loginButton": "Login", + "signupLink": "Don't have an account? Sign up", + "errors": { + "emailRequired": "Email is required", + "emailInvalid": "Invalid email format", + "passwordRequired": "Password is required", + "loginFailed": "Login failed. Please check your credentials." + }, + "notifications": { + "loginSuccess": "Login successful" + } + }, + "listsPage": { + "retryButton": "Retry", + "emptyState": { + "noListsForGroup": "No lists found for this group.", + "noListsYet": "You have no lists yet.", + "personalGlobalInfo": "Create a personal list or join a group to see shared lists.", + "groupSpecificInfo": "This group doesn't have any lists yet." + }, + "createNewListButton": "Create New List", + "loadingLists": "Loading lists...", + "noDescription": "No description", + "addItemPlaceholder": "Add new item...", + "createCard": { + "title": "+ Create a new list" + }, + "pageTitle": { + "forGroup": "Lists for {groupName}", + "forGroupId": "Lists for Group {groupId}", + "myLists": "My Lists" + }, + "errors": { + "fetchFailed": "Failed to fetch lists." + } + }, + "groupsPage": { + "retryButton": "Retry", + "emptyState": { + "title": "No Groups Yet!", + "description": "You are not a member of any groups yet. Create one or join using an invite code.", + "createButton": "Create New Group" + }, + "groupCard": { + "newListButton": "List" + }, + "createCard": { + "title": "+ Group" + }, + "joinGroup": { + "title": "Join a Group with Invite Code", + "inputLabel": "Enter Invite Code", + "inputPlaceholder": "Enter Invite Code", + "joinButton": "Join" + }, + "createDialog": { + "title": "Create New Group", + "closeButtonLabel": "Close", + "groupNameLabel": "Group Name", + "cancelButton": "Cancel", + "createButton": "Create" + }, + "errors": { + "fetchFailed": "Failed to load groups", + "groupNameRequired": "Group name is required", + "createFailed": "Failed to create group. Please try again.", + "inviteCodeRequired": "Invite code is required", + "joinFailed": "Failed to join group. Please check the invite code and try again." + }, + "notifications": { + "groupCreatedSuccess": "Group '{groupName}' created successfully.", + "joinSuccessNamed": "Successfully joined group '{groupName}'.", + "joinSuccessGeneric": "Successfully joined group.", + "listCreatedSuccess": "List '{listName}' created successfully." + } + }, + "authCallbackPage": { + "redirecting": "Redirecting...", + "errors": { + "authenticationFailed": "Authentication failed" + } + }, + "choresPage": { + "title": "Chores", + "tabs": { + "overdue": "Overdue", + "today": "Today", + "upcoming": "Upcoming", + "allPending": "All Pending", + "completed": "Completed" + }, + "viewToggle": { + "calendarLabel": "Calendar View", + "calendarText": "Calendar", + "listLabel": "List View", + "listText": "List" + }, + "newChoreButtonLabel": "New Chore", + "newChoreButtonText": "New Chore", + "loadingState": { + "loadingChores": "Loading chores..." + }, + "calendar": { + "prevMonthLabel": "Previous month", + "nextMonthLabel": "Next month", + "weekdays": { + "sun": "Sun", + "mon": "Mon", + "tue": "Tue", + "wed": "Wed", + "thu": "Thu", + "fri": "Fri", + "sat": "Sat" + }, + "addChoreToDayLabel": "Add chore to this day", + "emptyState": "No chores to display for this period." + }, + "listView": { + "choreTypePersonal": "Personal", + "choreTypeGroupFallback": "Group", + "completedDatePrefix": "Completed:", + "actions": { + "doneTitle": "Mark as Done", + "doneText": "Done", + "undoTitle": "Mark as Not Done", + "undoText": "Undo", + "editTitle": "Edit", + "editLabel": "Edit chore", + "editText": "Edit", + "deleteTitle": "Delete", + "deleteLabel": "Delete chore", + "deleteText": "Delete" + }, + "emptyState": { + "message": "No chores in this view. Well done!", + "viewAllButton": "View All Pending" + } + }, + "choreModal": { + "editTitle": "Edit Chore", + "newTitle": "New Chore", + "closeButtonLabel": "Close modal", + "nameLabel": "Name", + "namePlaceholder": "Enter chore name", + "typeLabel": "Type", + "typePersonal": "Personal", + "typeGroup": "Group", + "groupLabel": "Group", + "groupSelectDefault": "Select a group", + "descriptionLabel": "Description", + "descriptionPlaceholder": "Add a description (optional)", + "frequencyLabel": "Frequency", + "intervalLabel": "Interval (days)", + "intervalPlaceholder": "e.g. 3", + "dueDateLabel": "Due Date", + "quickDueDateToday": "Today", + "quickDueDateTomorrow": "Tomorrow", + "quickDueDateNextWeek": "Next Week", + "cancelButton": "Cancel", + "saveButton": "Save" + }, + "deleteDialog": { + "title": "Delete Chore", + "confirmationText": "Are you sure you want to delete this chore? This action cannot be undone.", + "deleteButton": "Delete" + }, + "shortcutsModal": { + "title": "Keyboard Shortcuts", + "descNewChore": "New Chore", + "descToggleView": "Toggle View (List/Calendar)", + "descToggleShortcuts": "Show/Hide Shortcuts", + "descCloseModal": "Close any open Modal/Dialog" + }, + "frequencyOptions": { + "oneTime": "One Time", + "daily": "Daily", + "weekly": "Weekly", + "monthly": "Monthly", + "custom": "Custom" + }, + "formatters": { + "noDueDate": "No due date", + "dueToday": "Due Today", + "dueTomorrow": "Due Tomorrow", + "overdueFull": "Overdue: {date}", + "dueFull": "Due {date}", + "invalidDate": "Invalid Date" + }, + "notifications": { + "loadFailed": "Failed to load chores", + "updateSuccess": "Chore '{name}' updated successfully", + "createSuccess": "Chore '{name}' created successfully", + "updateFailed": "Failed to update chore", + "createFailed": "Failed to create chore", + "deleteSuccess": "Chore '{name}' deleted successfully", + "deleteFailed": "Failed to delete chore", + "markedDone": "{name} marked as done.", + "markedNotDone": "{name} marked as not done.", + "statusUpdateFailed": "Failed to update chore status." + }, + "validation": { + "nameRequired": "Chore name is required.", + "groupRequired": "Please select a group for group chores.", + "intervalRequired": "Custom interval must be at least 1 day.", + "dueDateRequired": "Due date is required.", + "invalidDueDate": "Invalid due date format." + }, + "unsavedChangesConfirmation": "You have unsaved changes in the chore form. Are you sure you want to leave?" + }, + "errorNotFoundPage": { + "errorCode": "404", + "errorMessage": "Oops. Nothing here...", + "goHomeButton": "Go Home" + }, + "groupDetailPage": { + "loadingLabel": "Loading group details...", + "retryButton": "Retry", + "groupNotFound": "Group not found or an error occurred.", + "members": { + "title": "Group Members", + "defaultRole": "Member", + "removeButton": "Remove", + "emptyState": "No members found." + }, + "invites": { + "title": "Invite Members", + "regenerateButton": "Regenerate Invite Code", + "generateButton": "Generate Invite Code", + "activeCodeLabel": "Current Active Invite Code:", + "copyButtonLabel": "Copy invite code", + "copySuccess": "Invite code copied to clipboard!", + "emptyState": "No active invite code. Click the button above to generate one.", + "errors": { + "newDataInvalid": "New invite code data is invalid." + } + }, + "chores": { + "title": "Group Chores", + "manageButton": "Manage Chores", + "duePrefix": "Due:", + "emptyState": "No chores scheduled. Click \"Manage Chores\" to create some!" + }, + "expenses": { + "title": "Group Expenses", + "manageButton": "Manage Expenses", + "emptyState": "No expenses recorded. Click \"Manage Expenses\" to add some!", + "splitTypes": { + "equal": "Equal", + "exactAmounts": "Exact Amounts", + "percentage": "Percentage", + "shares": "Shares", + "itemBased": "Item Based" + } + }, + "notifications": { + "fetchDetailsFailed": "Failed to fetch group details.", + "fetchInviteFailed": "Failed to fetch active invite code.", + "generateInviteSuccess": "New invite code generated successfully!", + "generateInviteError": "Failed to generate invite code.", + "clipboardNotSupported": "Clipboard not supported or no code to copy.", + "copyInviteFailed": "Failed to copy invite code.", + "removeMemberSuccess": "Member removed successfully", + "removeMemberFailed": "Failed to remove member" + } + } +} diff --git a/fe/src/i18n/es.json b/fe/src/i18n/es.json new file mode 100644 index 0000000..b57d2e5 --- /dev/null +++ b/fe/src/i18n/es.json @@ -0,0 +1,274 @@ +{ + "message": { + "hello": "Hola" + }, + "loginPage": { + "emailLabel": "ES: Email", + "passwordLabel": "ES: Password", + "togglePasswordVisibilityLabel": "ES: Toggle password visibility", + "loginButton": "ES: Login", + "signupLink": "ES: Don't have an account? Sign up", + "errors": { + "emailRequired": "ES: Email is required", + "emailInvalid": "ES: Invalid email format", + "passwordRequired": "ES: Password is required", + "loginFailed": "ES: Login failed. Please check your credentials." + }, + "notifications": { + "loginSuccess": "ES: Login successful" + } + }, + "listsPage": { + "retryButton": "ES: Retry", + "emptyState": { + "noListsForGroup": "ES: No lists found for this group.", + "noListsYet": "ES: You have no lists yet.", + "personalGlobalInfo": "ES: Create a personal list or join a group to see shared lists.", + "groupSpecificInfo": "ES: This group doesn't have any lists yet." + }, + "createNewListButton": "ES: Create New List", + "loadingLists": "ES: Loading lists...", + "noDescription": "ES: No description", + "addItemPlaceholder": "ES: Add new item...", + "createCard": { + "title": "ES: + Create a new list" + }, + "pageTitle": { + "forGroup": "ES: Lists for {groupName}", + "forGroupId": "ES: Lists for Group {groupId}", + "myLists": "ES: My Lists" + }, + "errors": { + "fetchFailed": "ES: Failed to fetch lists." + } + }, + "groupsPage": { + "retryButton": "ES: Retry", + "emptyState": { + "title": "ES: No Groups Yet!", + "description": "ES: You are not a member of any groups yet. Create one or join using an invite code.", + "createButton": "ES: Create New Group" + }, + "groupCard": { + "newListButton": "ES: List" + }, + "createCard": { + "title": "ES: + Group" + }, + "joinGroup": { + "title": "ES: Join a Group with Invite Code", + "inputLabel": "ES: Enter Invite Code", + "inputPlaceholder": "ES: Enter Invite Code", + "joinButton": "ES: Join" + }, + "createDialog": { + "title": "ES: Create New Group", + "closeButtonLabel": "ES: Close", + "groupNameLabel": "ES: Group Name", + "cancelButton": "ES: Cancel", + "createButton": "ES: Create" + }, + "errors": { + "fetchFailed": "ES: Failed to load groups", + "groupNameRequired": "ES: Group name is required", + "createFailed": "ES: Failed to create group. Please try again.", + "inviteCodeRequired": "ES: Invite code is required", + "joinFailed": "ES: Failed to join group. Please check the invite code and try again." + }, + "notifications": { + "groupCreatedSuccess": "ES: Group '{groupName}' created successfully.", + "joinSuccessNamed": "ES: Successfully joined group '{groupName}'.", + "joinSuccessGeneric": "ES: Successfully joined group.", + "listCreatedSuccess": "ES: List '{listName}' created successfully." + } + }, + "authCallbackPage": { + "redirecting": "ES: Redirecting...", + "errors": { + "authenticationFailed": "ES: Authentication failed" + } + }, + "choresPage": { + "title": "ES: Chores", + "tabs": { + "overdue": "ES: Overdue", + "today": "ES: Today", + "upcoming": "ES: Upcoming", + "allPending": "ES: All Pending", + "completed": "ES: Completed" + }, + "viewToggle": { + "calendarLabel": "ES: Calendar View", + "calendarText": "ES: Calendar", + "listLabel": "ES: List View", + "listText": "ES: List" + }, + "newChoreButtonLabel": "ES: New Chore", + "newChoreButtonText": "ES: New Chore", + "loadingState": { + "loadingChores": "ES: Loading chores..." + }, + "calendar": { + "prevMonthLabel": "ES: Previous month", + "nextMonthLabel": "ES: Next month", + "weekdays": { + "sun": "ES: Sun", + "mon": "ES: Mon", + "tue": "ES: Tue", + "wed": "ES: Wed", + "thu": "ES: Thu", + "fri": "ES: Fri", + "sat": "ES: Sat" + }, + "addChoreToDayLabel": "ES: Add chore to this day", + "emptyState": "ES: No chores to display for this period." + }, + "listView": { + "choreTypePersonal": "ES: Personal", + "choreTypeGroupFallback": "ES: Group", + "completedDatePrefix": "ES: Completed:", + "actions": { + "doneTitle": "ES: Mark as Done", + "doneText": "ES: Done", + "undoTitle": "ES: Mark as Not Done", + "undoText": "ES: Undo", + "editTitle": "ES: Edit", + "editLabel": "ES: Edit chore", + "editText": "ES: Edit", + "deleteTitle": "ES: Delete", + "deleteLabel": "ES: Delete chore", + "deleteText": "ES: Delete" + }, + "emptyState": { + "message": "ES: No chores in this view. Well done!", + "viewAllButton": "ES: View All Pending" + } + }, + "choreModal": { + "editTitle": "ES: Edit Chore", + "newTitle": "ES: New Chore", + "closeButtonLabel": "ES: Close modal", + "nameLabel": "ES: Name", + "namePlaceholder": "ES: Enter chore name", + "typeLabel": "ES: Type", + "typePersonal": "ES: Personal", + "typeGroup": "ES: Group", + "groupLabel": "ES: Group", + "groupSelectDefault": "ES: Select a group", + "descriptionLabel": "ES: Description", + "descriptionPlaceholder": "ES: Add a description (optional)", + "frequencyLabel": "ES: Frequency", + "intervalLabel": "ES: Interval (days)", + "intervalPlaceholder": "ES: e.g. 3", + "dueDateLabel": "ES: Due Date", + "quickDueDateToday": "ES: Today", + "quickDueDateTomorrow": "ES: Tomorrow", + "quickDueDateNextWeek": "ES: Next Week", + "cancelButton": "ES: Cancel", + "saveButton": "ES: Save" + }, + "deleteDialog": { + "title": "ES: Delete Chore", + "confirmationText": "ES: Are you sure you want to delete this chore? This action cannot be undone.", + "deleteButton": "ES: Delete" + }, + "shortcutsModal": { + "title": "ES: Keyboard Shortcuts", + "descNewChore": "ES: New Chore", + "descToggleView": "ES: Toggle View (List/Calendar)", + "descToggleShortcuts": "ES: Show/Hide Shortcuts", + "descCloseModal": "ES: Close any open Modal/Dialog" + }, + "frequencyOptions": { + "oneTime": "ES: One Time", + "daily": "ES: Daily", + "weekly": "ES: Weekly", + "monthly": "ES: Monthly", + "custom": "ES: Custom" + }, + "formatters": { + "noDueDate": "ES: No due date", + "dueToday": "ES: Due Today", + "dueTomorrow": "ES: Due Tomorrow", + "overdueFull": "ES: Overdue: {date}", + "dueFull": "ES: Due {date}", + "invalidDate": "ES: Invalid Date" + }, + "notifications": { + "loadFailed": "ES: Failed to load chores", + "updateSuccess": "ES: Chore '{name}' updated successfully", + "createSuccess": "ES: Chore '{name}' created successfully", + "updateFailed": "ES: Failed to update chore", + "createFailed": "ES: Failed to create chore", + "deleteSuccess": "ES: Chore '{name}' deleted successfully", + "deleteFailed": "ES: Failed to delete chore", + "markedDone": "ES: {name} marked as done.", + "markedNotDone": "ES: {name} marked as not done.", + "statusUpdateFailed": "ES: Failed to update chore status." + }, + "validation": { + "nameRequired": "ES: Chore name is required.", + "groupRequired": "ES: Please select a group for group chores.", + "intervalRequired": "ES: Custom interval must be at least 1 day.", + "dueDateRequired": "ES: Due date is required.", + "invalidDueDate": "ES: Invalid due date format." + }, + "unsavedChangesConfirmation": "ES: You have unsaved changes in the chore form. Are you sure you want to leave?" + }, + "errorNotFoundPage": { + "errorCode": "ES: 404", + "errorMessage": "ES: Oops. Nothing here...", + "goHomeButton": "ES: Go Home" + }, + "groupDetailPage": { + "loadingLabel": "ES: Loading group details...", + "retryButton": "ES: Retry", + "groupNotFound": "ES: Group not found or an error occurred.", + "members": { + "title": "ES: Group Members", + "defaultRole": "ES: Member", + "removeButton": "ES: Remove", + "emptyState": "ES: No members found." + }, + "invites": { + "title": "ES: Invite Members", + "regenerateButton": "ES: Regenerate Invite Code", + "generateButton": "ES: Generate Invite Code", + "activeCodeLabel": "ES: Current Active Invite Code:", + "copyButtonLabel": "ES: Copy invite code", + "copySuccess": "ES: Invite code copied to clipboard!", + "emptyState": "ES: No active invite code. Click the button above to generate one.", + "errors": { + "newDataInvalid": "ES: New invite code data is invalid." + } + }, + "chores": { + "title": "ES: Group Chores", + "manageButton": "ES: Manage Chores", + "duePrefix": "ES: Due:", + "emptyState": "ES: No chores scheduled. Click \"Manage Chores\" to create some!" + }, + "expenses": { + "title": "ES: Group Expenses", + "manageButton": "ES: Manage Expenses", + "emptyState": "ES: No expenses recorded. Click \"Manage Expenses\" to add some!", + "splitTypes": { + "equal": "ES: Equal", + "exactAmounts": "ES: Exact Amounts", + "percentage": "ES: Percentage", + "shares": "ES: Shares", + "itemBased": "ES: Item Based" + } + }, + "notifications": { + "fetchDetailsFailed": "ES: Failed to fetch group details.", + "fetchInviteFailed": "ES: Failed to fetch active invite code.", + "generateInviteSuccess": "ES: New invite code generated successfully!", + "generateInviteError": "ES: Failed to generate invite code.", + "clipboardNotSupported": "ES: Clipboard not supported or no code to copy.", + "copyInviteFailed": "ES: Failed to copy invite code.", + "removeMemberSuccess": "ES: Member removed successfully", + "removeMemberFailed": "ES: Failed to remove member" + } + } +} diff --git a/fe/src/i18n/fr.json b/fe/src/i18n/fr.json new file mode 100644 index 0000000..0251c52 --- /dev/null +++ b/fe/src/i18n/fr.json @@ -0,0 +1,274 @@ +{ + "message": { + "hello": "Bonjour" + }, + "loginPage": { + "emailLabel": "FR: Email", + "passwordLabel": "FR: Password", + "togglePasswordVisibilityLabel": "FR: Toggle password visibility", + "loginButton": "FR: Login", + "signupLink": "FR: Don't have an account? Sign up", + "errors": { + "emailRequired": "FR: Email is required", + "emailInvalid": "FR: Invalid email format", + "passwordRequired": "FR: Password is required", + "loginFailed": "FR: Login failed. Please check your credentials." + }, + "notifications": { + "loginSuccess": "FR: Login successful" + } + }, + "listsPage": { + "retryButton": "FR: Retry", + "emptyState": { + "noListsForGroup": "FR: No lists found for this group.", + "noListsYet": "FR: You have no lists yet.", + "personalGlobalInfo": "FR: Create a personal list or join a group to see shared lists.", + "groupSpecificInfo": "FR: This group doesn't have any lists yet." + }, + "createNewListButton": "FR: Create New List", + "loadingLists": "FR: Loading lists...", + "noDescription": "FR: No description", + "addItemPlaceholder": "FR: Add new item...", + "createCard": { + "title": "FR: + Create a new list" + }, + "pageTitle": { + "forGroup": "FR: Lists for {groupName}", + "forGroupId": "FR: Lists for Group {groupId}", + "myLists": "FR: My Lists" + }, + "errors": { + "fetchFailed": "FR: Failed to fetch lists." + } + }, + "groupsPage": { + "retryButton": "FR: Retry", + "emptyState": { + "title": "FR: No Groups Yet!", + "description": "FR: You are not a member of any groups yet. Create one or join using an invite code.", + "createButton": "FR: Create New Group" + }, + "groupCard": { + "newListButton": "FR: List" + }, + "createCard": { + "title": "FR: + Group" + }, + "joinGroup": { + "title": "FR: Join a Group with Invite Code", + "inputLabel": "FR: Enter Invite Code", + "inputPlaceholder": "FR: Enter Invite Code", + "joinButton": "FR: Join" + }, + "createDialog": { + "title": "FR: Create New Group", + "closeButtonLabel": "FR: Close", + "groupNameLabel": "FR: Group Name", + "cancelButton": "FR: Cancel", + "createButton": "FR: Create" + }, + "errors": { + "fetchFailed": "FR: Failed to load groups", + "groupNameRequired": "FR: Group name is required", + "createFailed": "FR: Failed to create group. Please try again.", + "inviteCodeRequired": "FR: Invite code is required", + "joinFailed": "FR: Failed to join group. Please check the invite code and try again." + }, + "notifications": { + "groupCreatedSuccess": "FR: Group '{groupName}' created successfully.", + "joinSuccessNamed": "FR: Successfully joined group '{groupName}'.", + "joinSuccessGeneric": "FR: Successfully joined group.", + "listCreatedSuccess": "FR: List '{listName}' created successfully." + } + }, + "authCallbackPage": { + "redirecting": "FR: Redirecting...", + "errors": { + "authenticationFailed": "FR: Authentication failed" + } + }, + "choresPage": { + "title": "FR: Chores", + "tabs": { + "overdue": "FR: Overdue", + "today": "FR: Today", + "upcoming": "FR: Upcoming", + "allPending": "FR: All Pending", + "completed": "FR: Completed" + }, + "viewToggle": { + "calendarLabel": "FR: Calendar View", + "calendarText": "FR: Calendar", + "listLabel": "FR: List View", + "listText": "FR: List" + }, + "newChoreButtonLabel": "FR: New Chore", + "newChoreButtonText": "FR: New Chore", + "loadingState": { + "loadingChores": "FR: Loading chores..." + }, + "calendar": { + "prevMonthLabel": "FR: Previous month", + "nextMonthLabel": "FR: Next month", + "weekdays": { + "sun": "FR: Sun", + "mon": "FR: Mon", + "tue": "FR: Tue", + "wed": "FR: Wed", + "thu": "FR: Thu", + "fri": "FR: Fri", + "sat": "FR: Sat" + }, + "addChoreToDayLabel": "FR: Add chore to this day", + "emptyState": "FR: No chores to display for this period." + }, + "listView": { + "choreTypePersonal": "FR: Personal", + "choreTypeGroupFallback": "FR: Group", + "completedDatePrefix": "FR: Completed:", + "actions": { + "doneTitle": "FR: Mark as Done", + "doneText": "FR: Done", + "undoTitle": "FR: Mark as Not Done", + "undoText": "FR: Undo", + "editTitle": "FR: Edit", + "editLabel": "FR: Edit chore", + "editText": "FR: Edit", + "deleteTitle": "FR: Delete", + "deleteLabel": "FR: Delete chore", + "deleteText": "FR: Delete" + }, + "emptyState": { + "message": "FR: No chores in this view. Well done!", + "viewAllButton": "FR: View All Pending" + } + }, + "choreModal": { + "editTitle": "FR: Edit Chore", + "newTitle": "FR: New Chore", + "closeButtonLabel": "FR: Close modal", + "nameLabel": "FR: Name", + "namePlaceholder": "FR: Enter chore name", + "typeLabel": "FR: Type", + "typePersonal": "FR: Personal", + "typeGroup": "FR: Group", + "groupLabel": "FR: Group", + "groupSelectDefault": "FR: Select a group", + "descriptionLabel": "FR: Description", + "descriptionPlaceholder": "FR: Add a description (optional)", + "frequencyLabel": "FR: Frequency", + "intervalLabel": "FR: Interval (days)", + "intervalPlaceholder": "FR: e.g. 3", + "dueDateLabel": "FR: Due Date", + "quickDueDateToday": "FR: Today", + "quickDueDateTomorrow": "FR: Tomorrow", + "quickDueDateNextWeek": "FR: Next Week", + "cancelButton": "FR: Cancel", + "saveButton": "FR: Save" + }, + "deleteDialog": { + "title": "FR: Delete Chore", + "confirmationText": "FR: Are you sure you want to delete this chore? This action cannot be undone.", + "deleteButton": "FR: Delete" + }, + "shortcutsModal": { + "title": "FR: Keyboard Shortcuts", + "descNewChore": "FR: New Chore", + "descToggleView": "FR: Toggle View (List/Calendar)", + "descToggleShortcuts": "FR: Show/Hide Shortcuts", + "descCloseModal": "FR: Close any open Modal/Dialog" + }, + "frequencyOptions": { + "oneTime": "FR: One Time", + "daily": "FR: Daily", + "weekly": "FR: Weekly", + "monthly": "FR: Monthly", + "custom": "FR: Custom" + }, + "formatters": { + "noDueDate": "FR: No due date", + "dueToday": "FR: Due Today", + "dueTomorrow": "FR: Due Tomorrow", + "overdueFull": "FR: Overdue: {date}", + "dueFull": "FR: Due {date}", + "invalidDate": "FR: Invalid Date" + }, + "notifications": { + "loadFailed": "FR: Failed to load chores", + "updateSuccess": "FR: Chore '{name}' updated successfully", + "createSuccess": "FR: Chore '{name}' created successfully", + "updateFailed": "FR: Failed to update chore", + "createFailed": "FR: Failed to create chore", + "deleteSuccess": "FR: Chore '{name}' deleted successfully", + "deleteFailed": "FR: Failed to delete chore", + "markedDone": "FR: {name} marked as done.", + "markedNotDone": "FR: {name} marked as not done.", + "statusUpdateFailed": "FR: Failed to update chore status." + }, + "validation": { + "nameRequired": "FR: Chore name is required.", + "groupRequired": "FR: Please select a group for group chores.", + "intervalRequired": "FR: Custom interval must be at least 1 day.", + "dueDateRequired": "FR: Due date is required.", + "invalidDueDate": "FR: Invalid due date format." + }, + "unsavedChangesConfirmation": "FR: You have unsaved changes in the chore form. Are you sure you want to leave?" + }, + "errorNotFoundPage": { + "errorCode": "FR: 404", + "errorMessage": "FR: Oops. Nothing here...", + "goHomeButton": "FR: Go Home" + }, + "groupDetailPage": { + "loadingLabel": "FR: Loading group details...", + "retryButton": "FR: Retry", + "groupNotFound": "FR: Group not found or an error occurred.", + "members": { + "title": "FR: Group Members", + "defaultRole": "FR: Member", + "removeButton": "FR: Remove", + "emptyState": "FR: No members found." + }, + "invites": { + "title": "FR: Invite Members", + "regenerateButton": "FR: Regenerate Invite Code", + "generateButton": "FR: Generate Invite Code", + "activeCodeLabel": "FR: Current Active Invite Code:", + "copyButtonLabel": "FR: Copy invite code", + "copySuccess": "FR: Invite code copied to clipboard!", + "emptyState": "FR: No active invite code. Click the button above to generate one.", + "errors": { + "newDataInvalid": "FR: New invite code data is invalid." + } + }, + "chores": { + "title": "FR: Group Chores", + "manageButton": "FR: Manage Chores", + "duePrefix": "FR: Due:", + "emptyState": "FR: No chores scheduled. Click \"Manage Chores\" to create some!" + }, + "expenses": { + "title": "FR: Group Expenses", + "manageButton": "FR: Manage Expenses", + "emptyState": "FR: No expenses recorded. Click \"Manage Expenses\" to add some!", + "splitTypes": { + "equal": "FR: Equal", + "exactAmounts": "FR: Exact Amounts", + "percentage": "FR: Percentage", + "shares": "FR: Shares", + "itemBased": "FR: Item Based" + } + }, + "notifications": { + "fetchDetailsFailed": "FR: Failed to fetch group details.", + "fetchInviteFailed": "FR: Failed to fetch active invite code.", + "generateInviteSuccess": "FR: New invite code generated successfully!", + "generateInviteError": "FR: Failed to generate invite code.", + "clipboardNotSupported": "FR: Clipboard not supported or no code to copy.", + "copyInviteFailed": "FR: Failed to copy invite code.", + "removeMemberSuccess": "FR: Member removed successfully", + "removeMemberFailed": "FR: Failed to remove member" + } + } +} diff --git a/fe/src/i18n/index.ts b/fe/src/i18n/index.ts index 5851f87..f9c5e18 100644 --- a/fe/src/i18n/index.ts +++ b/fe/src/i18n/index.ts @@ -1,5 +1,11 @@ -import enUS from './en-US'; +import en from './en.json'; // Changed from enUS and path +import de from './de.json'; +import fr from './fr.json'; +import es from './es.json'; export default { - 'en-US': enUS + 'en': en, // Changed from 'en-US': enUS + 'de': de, + 'fr': fr, + 'es': es }; diff --git a/fe/src/main.ts b/fe/src/main.ts index 2a271cb..9c71ae5 100644 --- a/fe/src/main.ts +++ b/fe/src/main.ts @@ -4,8 +4,8 @@ import * as Sentry from '@sentry/vue'; import { BrowserTracing } from '@sentry/tracing'; import App from './App.vue'; import router from './router'; -// import { createI18n } from 'vue-i18n'; -// import messages from '@/i18n'; // Import from absolute path +import { createI18n } from 'vue-i18n'; +import messages from '@/i18n'; // Global styles import './assets/main.scss'; @@ -15,21 +15,22 @@ import { api, globalAxios } from '@/services/api'; // Renamed from boot/axios to import { useAuthStore } from '@/stores/auth'; // Vue I18n setup (from your i18n boot file) -// export type MessageLanguages = keyof typeof messages; -// export type MessageSchema = (typeof messages)['en-US']; +// // export type MessageLanguages = keyof typeof messages; +// // export type MessageSchema = (typeof messages)['en-US']; -// declare module 'vue-i18n' { -// export interface DefineLocaleMessage extends MessageSchema {} -// // eslint-disable-next-line @typescript-eslint/no-empty-object-type -// export interface DefineDateTimeFormat {} -// // eslint-disable-next-line @typescript-eslint/no-empty-object-type -// export interface DefineNumberFormat {} -// } -// const i18n = createI18n<{ message: MessageSchema }>({ -// locale: 'en-US', -// fallbackLocale: 'en-US', -// messages, -// }); +// // declare module 'vue-i18n' { +// // export interface DefineLocaleMessage extends MessageSchema {} +// // // eslint-disable-next-line @typescript-eslint/no-empty-object-type +// // export interface DefineDateTimeFormat {} +// // // eslint-disable-next-line @typescript-eslint/no-empty-object-type +// // export interface DefineNumberFormat {} +// // } +const i18n = createI18n({ + legacy: false, // Recommended for Vue 3 + locale: 'en', // Default locale + fallbackLocale: 'en', // Fallback locale + messages, +}); const app = createApp(App); const pinia = createPinia(); @@ -62,7 +63,7 @@ if (authStore.accessToken) { } app.use(router); -// app.use(i18n); +app.use(i18n); // Make API instance globally available (optional, prefer provide/inject or store) app.config.globalProperties.$api = api; diff --git a/fe/src/pages/AuthCallbackPage.vue b/fe/src/pages/AuthCallbackPage.vue index 874fc12..81ed4d7 100644 --- a/fe/src/pages/AuthCallbackPage.vue +++ b/fe/src/pages/AuthCallbackPage.vue @@ -6,7 +6,7 @@

{{ error }}

-

Redirecting...

+

{{ t('authCallbackPage.redirecting') }}

@@ -14,6 +14,7 @@ diff --git a/fe/src/pages/GroupDetailPage.vue b/fe/src/pages/GroupDetailPage.vue index 1c9ca17..ac34505 100644 --- a/fe/src/pages/GroupDetailPage.vue +++ b/fe/src/pages/GroupDetailPage.vue @@ -1,11 +1,11 @@