From 00b292e827be801cf073ccadbc127eaa5188deaa Mon Sep 17 00:00:00 2001 From: Thomas Date: Fri, 17 Jan 2025 11:53:16 -0600 Subject: [PATCH 1/4] refactor(frontend): replace all i18n strings with i18nMap objects --- frontend/components/EmptyState.vue | 24 ++++---- frontend/components/FriendlyCaptcha.vue | 5 +- frontend/components/Loading.vue | 4 +- frontend/components/SearchBar.vue | 6 +- frontend/components/btn/BtnRoadMap.vue | 9 ++- frontend/components/btn/BtnShareIcon.vue | 3 +- frontend/components/card/CardConnect.vue | 13 ++-- frontend/components/card/CardDangerZone.vue | 12 ++-- frontend/components/card/CardDatePicker.vue | 7 ++- frontend/components/card/CardDetails.vue | 5 +- frontend/components/card/CardDonate.vue | 5 +- frontend/components/card/CardFAQEntry.vue | 5 +- .../components/card/CardLegalDisclaimer.vue | 3 +- .../components/card/CardMetricsOverview.vue | 12 ++-- .../card/CardOrgApplicationVote.vue | 3 +- .../components/card/CardTopicSelection.vue | 15 ++--- .../components/card/about/CardAboutEvent.vue | 11 ++-- .../components/card/about/CardAboutGroup.vue | 13 ++-- .../card/about/CardAboutOrganization.vue | 13 ++-- .../CardChangeAccountInfoEmail.vue | 23 +++++--- .../CardChangeAccountInfoPassword.vue | 23 +++++--- .../CardChangeAccountInfoUsername.vue | 19 +++--- .../card/discussion/CardDiscussionEntry.vue | 3 +- .../card/discussion/CardDiscussionInput.vue | 13 ++-- .../get-involved/CardGetInvolvedEvent.vue | 13 ++-- .../get-involved/CardGetInvolvedGroup.vue | 11 ++-- .../CardGetInvolvedOrganization.vue | 9 +-- .../card/search-result/CardSearchResult.vue | 7 ++- .../components/combobox/ComboboxTopics.vue | 3 +- .../discussion/DiscussionHeader.vue | 7 ++- .../components/dropdown/DropdownCreate.vue | 3 +- frontend/components/dropdown/DropdownInfo.vue | 3 +- .../components/dropdown/DropdownTheme.vue | 5 +- .../dropdown/DropdownUserOptions.vue | 5 +- frontend/components/feed/FeedItem.vue | 7 ++- .../components/footer/flex/FooterFlex.vue | 14 +++-- .../components/footer/flex/FooterFlexCol.vue | 14 +++-- frontend/components/form/FormViewSelector.vue | 3 +- .../components/form/radio/FormRadioGroup.vue | 5 +- frontend/components/grid/GridAppShields.vue | 13 ++-- .../components/grid/GridGitHubShields.vue | 9 +-- frontend/components/grid/GridSupporters.vue | 11 +++- frontend/components/header/HeaderAppPage.vue | 9 +-- frontend/components/icon/IconActivist.vue | 4 +- .../indicator/IndicatorPasswordStrength.vue | 5 +- .../indicator/IndicatorProcessProgress.vue | 5 +- .../landing/LandingCommunityBanner.vue | 13 ++-- frontend/components/landing/LandingSplash.vue | 12 ++-- .../components/landing/LandingTechBanner.vue | 11 +++- frontend/components/logo/LogoActivist.vue | 6 +- .../image-carousel/MediaImageCarousel.vue | 3 +- .../meta-tag/MetaTagOrganization.vue | 3 +- frontend/components/modal/ModalBase.vue | 5 +- .../components/modal/ModalCommandPalette.vue | 5 +- .../modal/ModalOrganizationOverview.vue | 3 +- .../modal/ModalOrganizationStatus.vue | 3 +- frontend/components/modal/ModalSharePage.vue | 23 ++++---- .../modal/edit/ModalEditFaqEntry.vue | 13 ++-- .../modal/edit/text/ModalEditTextEvent.vue | 14 +++-- .../modal/edit/text/ModalEditTextGroup.vue | 14 +++-- .../edit/text/ModalEditTextOrganization.vue | 13 ++-- .../components/modal/image/ModalImageBtn.vue | 4 +- .../components/modal/qr-code/ModalQRCode.vue | 47 +++++++-------- .../modal/qr-code/ModalQRCodeBtn.vue | 9 +-- .../modal/upload-images/ModalUploadImages.vue | 23 ++++---- frontend/components/page/PageBreadcrumbs.vue | 3 +- .../components/page/PageCommunityFooter.vue | 31 +++++----- frontend/components/page/PageFilter.vue | 7 ++- frontend/components/shield/ShieldPrivate.vue | 3 +- .../sidebar/left/SidebarLeftHeader.vue | 4 +- .../sidebar/left/SidebarLeftSelector.vue | 6 +- .../sidebar/left/index/SidebarLeftIndex.vue | 5 +- .../sidebar/right/SidebarRightHamburger.vue | 4 +- .../tooltip/TooltipDiscussionWarning.vue | 15 +++-- .../tooltip/TooltipPasswordRequirements.vue | 3 +- frontend/components/tooltip/TooltipSignIn.vue | 11 +++- .../TooltipMenuSearchResultEvent.vue | 7 ++- .../TooltipMenuSearchResultGroup.vue | 7 ++- .../TooltipMenuSearchResultOrganization.vue | 7 ++- .../TooltipMenuSearchResultResource.vue | 5 +- .../TooltipMenuSearchResultUser.vue | 5 +- frontend/error.vue | 6 +- frontend/i18n/check/run_i18n_checks.py | 2 +- frontend/pages/auth/index.vue | 7 ++- frontend/pages/auth/reset-password.vue | 12 ++-- frontend/pages/auth/set-password.vue | 11 ++-- frontend/pages/auth/sign-in.vue | 17 +++--- frontend/pages/auth/sign-up.vue | 15 ++--- frontend/pages/contact.vue | 59 ++++++++++--------- frontend/pages/events/[id]/about.vue | 3 +- frontend/pages/events/[id]/discussion.vue | 7 ++- frontend/pages/events/[id]/index.vue | 5 +- frontend/pages/events/[id]/resources.vue | 7 ++- frontend/pages/events/[id]/settings.vue | 12 ++-- frontend/pages/events/[id]/tasks.vue | 7 ++- frontend/pages/events/[id]/team.vue | 7 ++- frontend/pages/events/create.vue | 54 +++++++++-------- frontend/pages/events/index.vue | 8 ++- frontend/pages/events/search.vue | 11 +++- frontend/pages/groups/create.vue | 26 ++++---- frontend/pages/groups/index.vue | 8 ++- frontend/pages/home/index.vue | 11 +++- frontend/pages/index.vue | 7 ++- frontend/pages/organizations/[id]/about.vue | 3 +- .../pages/organizations/[id]/affiliates.vue | 8 ++- .../organizations/[id]/discussions/index.vue | 7 ++- frontend/pages/organizations/[id]/events.vue | 7 ++- frontend/pages/organizations/[id]/faq.vue | 7 ++- .../[id]/groups/[group-id]/about.vue | 3 +- .../[id]/groups/[group-id]/events.vue | 8 ++- .../[id]/groups/[group-id]/faq.vue | 7 ++- .../[id]/groups/[group-id]/resources.vue | 7 ++- .../pages/organizations/[id]/groups/index.vue | 7 ++- frontend/pages/organizations/[id]/index.vue | 5 +- .../pages/organizations/[id]/resources.vue | 7 ++- .../pages/organizations/[id]/settings.vue | 12 ++-- frontend/pages/organizations/[id]/tasks.vue | 7 ++- frontend/pages/organizations/[id]/team.vue | 7 ++- frontend/pages/organizations/create.vue | 25 ++++---- frontend/pages/organizations/index.vue | 8 ++- frontend/pages/organizations/search.vue | 11 +++- frontend/pages/resources/create.vue | 26 ++++---- frontend/pages/resources/index.vue | 8 ++- frontend/pages/search/index.vue | 11 +++- 124 files changed, 731 insertions(+), 523 deletions(-) diff --git a/frontend/components/EmptyState.vue b/frontend/components/EmptyState.vue index a2515546..57717163 100644 --- a/frontend/components/EmptyState.vue +++ b/frontend/components/EmptyState.vue @@ -8,36 +8,36 @@
{{ - $t("components.empty_state.organizations_header") + $t(i18nMap.components.empty_state.organizations_header) }} {{ - $t("components.empty_state.groups_header") + $t(i18nMap.components.empty_state.groups_header) }} {{ - $t("components.empty_state.events_header") + $t(i18nMap.components.empty_state.events_header) }} {{ - $t("components.empty_state.resources_header") + $t(i18nMap.components.empty_state.resources_header) }} {{ - $t("components.empty_state.faq_header") + $t(i18nMap.components.empty_state.faq_header) }} {{ - $t("components.empty_state.team_header") + $t(i18nMap.components.empty_state.team_header) }} {{ - $t("components.empty_state.affiliates_header") + $t(i18nMap.components.empty_state.affiliates_header) }} {{ - $t("components.empty_state.tasks_header") + $t(i18nMap.components.empty_state.tasks_header) }} {{ - $t("components.empty_state.discussions_header") + $t(i18nMap.components.empty_state.discussions_header) }}
{{ - $t("components.empty_state.message_no_permission") + $t(i18nMap.components.empty_state.message_no_permission) }}
{{ - $t("components.empty_state.message_with_permission") + $t(i18nMap.components.empty_state.message_with_permission) }}
+ diff --git a/frontend/components/btn/BtnShareIcon.vue b/frontend/components/btn/BtnShareIcon.vue index 26d58ab9..d53a473a 100644 --- a/frontend/components/btn/BtnShareIcon.vue +++ b/frontend/components/btn/BtnShareIcon.vue @@ -40,7 +40,7 @@ v-if="contentCopied" class="text-accepted-green hover:text-accepted-green dark:text-accepted-green dark:hover:text-accepted-green" :iconName="IconMap.SQUARE_CHECK" - :text="$t('components.btn_share_icon.url_copied')" + :text="$t(i18nMap.components.btn_share_icon.url_copied)" :iconSize="iconSize" />
@@ -59,6 +59,7 @@ import { ref, type Component } from "vue"; import { IconMap } from "~/types/icon-map"; import { toast } from "vue-sonner"; import { useI18n } from "vue-i18n"; +import { i18nMap } from "~/types/i18n-map"; const vueSocials: { [key: string]: Component } = { SEmail, diff --git a/frontend/components/card/CardConnect.vue b/frontend/components/card/CardConnect.vue index ab47958f..f98f5f58 100644 --- a/frontend/components/card/CardConnect.vue +++ b/frontend/components/card/CardConnect.vue @@ -3,7 +3,7 @@

- {{ $t("components._global.connect") }} + {{ $t(i18nMap.components._global.connect) }}

@@ -114,6 +114,7 @@ import { Popover, PopoverButton, PopoverPanel } from "@headlessui/vue"; import type { Group } from "~/types/communities/group"; import type { Organization } from "~/types/communities/organization"; import type { Event } from "~/types/events/event"; +import { i18nMap } from "~/types/i18n-map"; import { IconMap } from "~/types/icon-map"; const props = defineProps<{ diff --git a/frontend/components/card/CardDangerZone.vue b/frontend/components/card/CardDangerZone.vue index 0ac64cfe..0be931ef 100644 --- a/frontend/components/card/CardDangerZone.vue +++ b/frontend/components/card/CardDangerZone.vue @@ -5,7 +5,7 @@ >

- {{ $t("components.card_danger_zone.header") }} + {{ $t(i18nMap.components.card_danger_zone.header) }}

{{ description }}

@@ -17,10 +17,10 @@ class="responsive-h4 font-bold text-primary-text" for="username" :placeholder=" - $t('components.card_danger_zone.username_placeholder') + $t(i18nMap.components.card_danger_zone.username_placeholder) " > - {{ $t("components.card_danger_zone.username_label") }} * + {{ $t(i18nMap.components.card_danger_zone.username_label) }} * - {{ $t("components.card_danger_zone.password_label") }} * + {{ $t(i18nMap.components.card_danger_zone.password_label) }} * + - + + diff --git a/frontend/components/tooltip/TooltipPasswordRequirements.vue b/frontend/components/tooltip/TooltipPasswordRequirements.vue index 8e7d2424..57cd2e57 100644 --- a/frontend/components/tooltip/TooltipPasswordRequirements.vue +++ b/frontend/components/tooltip/TooltipPasswordRequirements.vue @@ -4,7 +4,9 @@ class="z-20 min-w-[200px] pb-4 pt-2 transition delay-150 ease-in-out md:min-w-[450px]" > {{ - $t(i18nMap.components.tooltip_password_requirements.password_rules_message) + $t( + i18nMap.components.tooltip_password_requirements.password_rules_message + ) }}
-import { i18nMap } from '~/types/i18n-map'; - - - + + diff --git a/frontend/components/tooltip/menu-search-result/TooltipMenuSearchResultUser.vue b/frontend/components/tooltip/menu-search-result/TooltipMenuSearchResultUser.vue index 5f2463e0..7f0732f0 100644 --- a/frontend/components/tooltip/menu-search-result/TooltipMenuSearchResultUser.vue +++ b/frontend/components/tooltip/menu-search-result/TooltipMenuSearchResultUser.vue @@ -21,7 +21,10 @@ :rightIcon="IconMap.SHARE" fontSize="lg" :ariaLabel=" - $t(i18nMap.components.tooltip_menu_search_result_user.share_user_aria_label) + $t( + i18nMap.components.tooltip_menu_search_result_user + .share_user_aria_label + ) " /> - + + diff --git a/frontend/pages/auth/reset-password.vue b/frontend/pages/auth/reset-password.vue index 11cb62bd..e0adafc9 100644 --- a/frontend/pages/auth/reset-password.vue +++ b/frontend/pages/auth/reset-password.vue @@ -2,7 +2,9 @@ - + + diff --git a/frontend/pages/groups/create.vue b/frontend/pages/groups/create.vue index 3d7ae547..c02a74c1 100644 --- a/frontend/pages/groups/create.vue +++ b/frontend/pages/groups/create.vue @@ -34,7 +34,9 @@ class="mt-2 w-full rounded-md border border-section-div bg-layer-0 px-4 py-2" type="text" name="name" - :placeholder="$t(i18nMap.pages.groups.create.group_name_placeholder)" + :placeholder=" + $t(i18nMap.pages.groups.create.group_name_placeholder) + " />
@@ -47,7 +49,9 @@ class="mt-2 w-full rounded-md border border-section-div bg-layer-0 px-4 py-2" type="text" name="location" - :placeholder="$t(i18nMap.pages.groups.create.location_placeholder)" + :placeholder=" + $t(i18nMap.pages.groups.create.location_placeholder) + " />
@@ -60,7 +64,9 @@ id="description" class="mt-2 w-full rounded-md border border-section-div bg-layer-0 px-4 py-2" name="description" - :placeholder="$t(i18nMap.pages.groups.create.description_placeholder)" + :placeholder=" + $t(i18nMap.pages.groups.create.description_placeholder) + " >
@@ -111,7 +117,7 @@ - + + diff --git a/frontend/pages/index.vue b/frontend/pages/index.vue index 5f55be8f..7ef7a85b 100644 --- a/frontend/pages/index.vue +++ b/frontend/pages/index.vue @@ -1,8 +1,3 @@ - - + + diff --git a/frontend/pages/organizations/[id]/affiliates.vue b/frontend/pages/organizations/[id]/affiliates.vue index 0923abfd..eb158999 100644 --- a/frontend/pages/organizations/[id]/affiliates.vue +++ b/frontend/pages/organizations/[id]/affiliates.vue @@ -38,7 +38,7 @@ - + + diff --git a/frontend/pages/resources/create.vue b/frontend/pages/resources/create.vue index 8e49353f..bb5259d1 100644 --- a/frontend/pages/resources/create.vue +++ b/frontend/pages/resources/create.vue @@ -62,7 +62,9 @@ id="description" class="mt-2 w-full rounded-md border border-section-div bg-layer-0 px-4 py-2" name="description" - :placeholder="$t(i18nMap.pages.resources.create.description_placeholder)" + :placeholder=" + $t(i18nMap.pages.resources.create.description_placeholder) + " >
@@ -75,7 +77,9 @@ id="location" class="mt-2 w-full rounded-md border border-section-div bg-layer-0 px-4 py-2" name="location" - :placeholder="$t(i18nMap.pages.resources.create.location_placeholder)" + :placeholder=" + $t(i18nMap.pages.resources.create.location_placeholder) + " >
@@ -112,7 +116,7 @@ - + + From c73eac36ca1a0f7e831a157bcea50f5ccf8f0c0b Mon Sep 17 00:00:00 2001 From: Andrew Tavis McAllister Date: Sun, 19 Jan 2025 00:12:26 +0100 Subject: [PATCH 3/4] Fix prettier for feed item component --- frontend/components/feed/FeedItem.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/components/feed/FeedItem.vue b/frontend/components/feed/FeedItem.vue index ad816426..c73b2c05 100644 --- a/frontend/components/feed/FeedItem.vue +++ b/frontend/components/feed/FeedItem.vue @@ -9,7 +9,7 @@ >
From bfa5a0fe7e67279a370d433fb1fb5c928ecde7ca Mon Sep 17 00:00:00 2001 From: Andrew Tavis McAllister Date: Sun, 19 Jan 2025 00:29:00 +0100 Subject: [PATCH 4/4] Update styleguide given i18nMap usage --- STYLEGUIDE.md | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/STYLEGUIDE.md b/STYLEGUIDE.md index 276ee2c9..cf799480 100644 --- a/STYLEGUIDE.md +++ b/STYLEGUIDE.md @@ -239,23 +239,28 @@ activist is a global platform and must function in countless different regions a > > - This is the source from which all the other languages are translated from > - Edits to the other files should be made on activist's [public localization project on Weblate](https://hosted.weblate.org/projects/activist/activist) -> - Do not put the JSON dictionaries into different levels! +> - Do not convert the JSON dictionaries into nested sub-objects! > - The purpose of the flat dictionaries is so that we can search for the key in the codebase and easily find its uses and where it's defined > - Do not include periods in aria-labels (screen reader user will configure their own preferences for a hard stop) Localization keys should be defined based on the file in which they're used within the platform and the content that they refer to (`CONTENT_REFERENCE` below). Please use the following rules as a guide if you find yourself needing to create new localization keys: +- Please use the `i18nMap` object for all texts within the frontend + - This object returns the sequence of object methods as a string and allows ESLint to be used to check key accuracy + - Ex: Using the `i18nMap` object: + - ✅ `i18nMap._global.about` + - ❌ `"_global.about"` - Separate directories and references by `.` and PascalCase/camelCase file name components by `_` in keys - - Ex: `"components.search_bar.CONTENT_REFERENCE"` for the `SearchBar` component + - Ex: `i18nMap.components.search_bar.CONTENT_REFERENCE` for the `SearchBar` component - Even though Nuxt allows for us to nest components in directories, avoid repetition in the directory path used to define the localization key - Ex: If you're defining a key within `CardAbout`: - - ✅ `"components.card_about.CONTENT_REFERENCE"` - - ❌ `"components.card.card_about.CONTENT_REFERENCE"` + - ✅ `i18nMap.components.card_about.CONTENT_REFERENCE` + - ❌ `i18nMap.components.card.card_about.CONTENT_REFERENCE` - Define keys based on the lowest level file in which they're used - Use `_global` to indicate that a key is used in multiple places in a given directory - Ex: You're creating a key that's used by multiple cards: - - ✅ `"components.card._global.CONTENT_REFERENCE"` - - ❌ `"components.card.INDIVIDUAL_COMPONENT.CONTENT_REFERENCE"` + - ✅ `i18nMap.components.card._global.CONTENT_REFERENCE` + - ❌ `i18nMap.components.card.INDIVIDUAL_COMPONENT.CONTENT_REFERENCE` - Please end all aria-label keys with `_alt_text` so the localization team knows that they're for screen readers - If you need a capitalized and lower case version of a word, signify the lower case version with `_lower` at the end of the key - For pages with long texts please follow the below naming criteria: @@ -274,7 +279,7 @@ Localization keys should be defined based on the file in which they're used with - This makes sure that content writers and the i18n team are only working with language that's actively in use > [!NOTE] -> The activist community also maintains the [i18n-check project](https://github.com/activist-org/i18n-check-action?tab=readme-ov-file#contentions) that enforces all of the above in pull requests. Do your best and we'll help you out during the PR process! You can also join us in the [localization room on Matrix](https://matrix.to/#/!DzbdYyfhjinQBWXgQe:matrix.org?via=matrix.org) if you have questions :) +> The activist community also maintains the [i18n-check project](https://github.com/activist-org/i18n-check) that enforces all of the above in pull requests. Do your best and we'll help you out during the PR process! You can also join us in the [localization room on Matrix](https://matrix.to/#/!DzbdYyfhjinQBWXgQe:matrix.org?via=matrix.org) if you have questions :)