Skip to content

Commit

Permalink
Merge pull request #1130 from activist-org/1097-i18n-check-invalid-keys
Browse files Browse the repository at this point in the history
#1097 Remove i18nMap and switch to regex based invalid key check
  • Loading branch information
andrewtavis authored Feb 18, 2025
2 parents a9fc84c + 4dc1fce commit 369f97f
Show file tree
Hide file tree
Showing 156 changed files with 3,567 additions and 4,869 deletions.
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ node_modules/
.nuxt/
.output/

dist/
playwright-report/
tests-examples/
test-results/
17 changes: 8 additions & 9 deletions STYLEGUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -234,22 +234,21 @@ activist is a global platform and must function in countless different regions a
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 [i18n-check](https://github.com/activist-org/i18n-check) `i18nMap` object for all texts within the frontend
- This object returns the sequence of object methods as a string and allows the type checker to be used to check key accuracy
- Ex: Using the `i18nMap` object:
-`i18nMap._global.foo`
- In following [i18n-check](https://github.com/activist-org/i18n-check) standards, please prepend all i18n keys with `i18n`
- This allows us to check all keys that are in use against those found in the `en-US.json` file
-`i18n._global.foo`
-`"_global.foo"`
- Separate directories and references by `.` and PascalCase/camelCase file name components by `_` in keys
- Ex: `i18nMap.components.landing_splash.CONTENT_REFERENCE` for the `LandingSplash` component
- Ex: `i18n.components.landing_splash.CONTENT_REFERENCE` for the `LandingSplash` 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`:
-`i18nMap.components.footer_flex.CONTENT_REFERENCE`
-`i18nMap.components.footer.footer_flex.CONTENT_REFERENCE`
-`i18n.components.footer_flex.CONTENT_REFERENCE`
-`i18n.components.footer.footer_flex.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 landing page components:
-`i18nMap.components.landing._global.CONTENT_REFERENCE`
-`i18nMap.components.landing.INDIVIDUAL_COMPONENT.CONTENT_REFERENCE`
-`i18n.components.landing._global.CONTENT_REFERENCE`
-`i18n.components.landing.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:
Expand Down
62 changes: 30 additions & 32 deletions frontend/components/EmptyState.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,56 +3,56 @@
<div class="flex w-full flex-col items-center bg-layer-0 text-primary-text">
<PageContent
:imgUrl="BOOTSTRAP_CLOUD_MOON_URL"
:imgAltText="i18nMap.components.empty_state.img_alt_text"
imgAltText="i18n.components.empty_state.img_alt_text"
>
<div>
<!-- Header -->
<span v-if="pageType == 'organizations'" class="responsive-h2">{{
$t(i18nMap.components.empty_state.organizations_header)
$t("i18n.components.empty_state.organizations_header")
}}</span>
<span v-if="pageType == 'groups'" class="responsive-h2">{{
$t(i18nMap.components.empty_state.groups_header)
$t("i18n.components.empty_state.groups_header")
}}</span>
<span v-if="pageType == 'events'" class="responsive-h2">{{
$t(i18nMap.components.empty_state.events_header)
$t("i18n.components.empty_state.events_header")
}}</span>
<span v-if="pageType == 'resources'" class="responsive-h2">{{
$t(i18nMap.components.empty_state.resources_header)
$t("i18n.components.empty_state.resources_header")
}}</span>
<span v-if="pageType == 'faq'" class="responsive-h2">{{
$t(i18nMap.components.empty_state.faq_header)
$t("i18n.components.empty_state.faq_header")
}}</span>
<span v-if="pageType == 'team'" class="responsive-h2">{{
$t(i18nMap.components.empty_state.team_header)
$t("i18n.components.empty_state.team_header")
}}</span>
<span v-if="pageType == 'affiliates'" class="responsive-h2">{{
$t(i18nMap.components.empty_state.affiliates_header)
$t("i18n.components.empty_state.affiliates_header")
}}</span>
<span v-if="pageType == 'tasks'" class="responsive-h2">{{
$t(i18nMap.components.empty_state.tasks_header)
$t("i18n.components.empty_state.tasks_header")
}}</span>
<span v-if="pageType == 'discussions'" class="responsive-h2">{{
$t(i18nMap.components.empty_state.discussions_header)
$t("i18n.components.empty_state.discussions_header")
}}</span>
<!-- Message -->
<div v-if="!permission" class="flex flex-col space-y-6 py-6">
<span class="responsive-h4">{{
$t(i18nMap.components.empty_state.message_no_permission)
$t("i18n.components.empty_state.message_no_permission")
}}</span>
<PageCommunityFooter
:header="i18nMap.components.empty_state.cta_header_no_permission"
header="i18n.components.empty_state.cta_header_no_permission"
><BtnRouteInternal
class="w-full"
:cta="false"
:label="i18nMap._global.return_home"
label="i18n._global.return_home"
linkTo="/home"
fontSize="lg"
:ariaLabel="i18nMap._global.return_home_aria_label"
ariaLabel="i18n._global.return_home_aria_label"
/></PageCommunityFooter>
</div>
<div v-else class="flex flex-col space-y-6 py-6">
<span class="responsive-h4">{{
$t(i18nMap.components.empty_state.message_with_permission)
$t("i18n.components.empty_state.message_with_permission")
}}</span>
<div
class="mx-auto grid max-w-[70%] grid-cols-1 gap-y-4 pb-6 sm:mx-0 sm:max-w-[90%] sm:grid-cols-2 sm:grid-rows-1 sm:gap-x-4 sm:gap-y-0 md:max-w-[70%] md:gap-x-6 lg:max-w-[60%] xl:max-w-[50%] xl:gap-x-8 2xl:max-w-[80%]"
Expand All @@ -61,57 +61,57 @@
v-if="pageType == 'organizations'"
class="w-full"
:cta="true"
:label="i18nMap.components.empty_state.create_organization"
label="i18n.components.empty_state.create_organization"
linkTo="/organizations/create"
fontSize="lg"
:ariaLabel="
i18nMap.components.empty_state.create_organization_aria_label
ariaLabel="
i18n.components.empty_state.create_organization_aria_label
"
/>
<BtnRouteInternal
v-if="pageType == 'groups'"
class="w-full"
:cta="true"
:label="i18nMap._global.create_group"
label="i18n._global.create_group"
linkTo="/groups/create"
fontSize="lg"
:ariaLabel="
i18nMap.components.empty_state.create_group_aria_label
ariaLabel="
i18n.components.empty_state.create_group_aria_label
"
/>
<BtnRouteInternal
v-if="pageType == 'events'"
class="w-full"
:cta="true"
:label="i18nMap.components.empty_state.create_event"
label="i18n.components.empty_state.create_event"
linkTo="/events/create"
fontSize="lg"
:ariaLabel="
i18nMap.components.empty_state.create_event_aria_label
ariaLabel="
i18n.components.empty_state.create_event_aria_label
"
/>
<BtnRouteInternal
v-if="pageType == 'resources'"
class="w-full"
:cta="true"
:label="i18nMap._global.create_resource"
label="i18n._global.create_resource"
linkTo="/resources/create"
fontSize="lg"
:ariaLabel="
i18nMap.components.empty_state.create_resource_aria_label
ariaLabel="
i18n.components.empty_state.create_resource_aria_label
"
/>
</div>
<PageCommunityFooter
:header="i18nMap.components.empty_state.cta_header_no_permission"
header="i18n.components.empty_state.cta_header_no_permission"
:helpNeeded="true"
><BtnRouteInternal
class="w-full"
:cta="false"
:label="i18nMap._global.return_home"
label="i18n._global.return_home"
linkTo="/home"
fontSize="lg"
:ariaLabel="i18nMap._global.return_home_aria_label"
ariaLabel="i18n._global.return_home_aria_label"
/></PageCommunityFooter>
</div>
</div>
Expand All @@ -120,8 +120,6 @@
</template>

<script setup lang="ts">
import { i18nMap } from "~/types/i18n-map";

defineProps<{
pageType:
| "organizations"
Expand Down
5 changes: 2 additions & 3 deletions frontend/components/FriendlyCaptcha.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,19 @@
class="style-btn flex w-full cursor-not-allowed items-center space-x-4 rounded-md border-none p-1 px-3 text-lg shadow-none"
:disabled="true"
:aria-label="
$t(i18nMap.components.friendly_captcha.captcha_disabled_aria_label)
$t('i18n.components.friendly_captcha.captcha_disabled_aria_label')
"
>
<Icon :name="IconMap.SHIELD" size="28px" />
<p class="font-bold">
{{ $t(i18nMap.components.friendly_captcha.captcha_disabled) }}
{{ $t("i18n.components.friendly_captcha.captcha_disabled") }}
</p>
</button>
</div>
</template>

<script setup lang="ts">
import VueFriendlyCaptcha from "@somushq/vue3-friendly-captcha";
import { i18nMap } from "~/types/i18n-map";
import { IconMap } from "~/types/icon-map";

const devMode = useDevMode();
Expand Down
4 changes: 2 additions & 2 deletions frontend/components/Loading.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,13 @@
v-if="$colorMode.value == 'light'"
class="h-40"
:src="ACTIVIST_ICON_LIGHT_URL"
:alt="$t(i18nMap._global.activist_icon_img_alt_text)"
:alt="$t('i18n._global.activist_icon_img_alt_text')"
/>
<img
v-else-if="$colorMode.value == 'dark'"
class="h-40"
:src="ACTIVIST_ICON_DARK_URL"
:alt="$t(i18nMap._global.activist_icon_img_alt_text)"
:alt="$t('i18n._global.activist_icon_img_alt_text')"
/>
</div>
</div> -->
Expand Down
15 changes: 7 additions & 8 deletions frontend/components/SearchBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
v-if="sidebar.collapsed == false || sidebar.collapsedSwitch == false"
>
<label for="input-search" class="sr-only">{{
$t(i18nMap._global.search)
$t("i18n._global.search")
}}</label>
<input
@focus="onFocus"
Expand All @@ -26,7 +26,7 @@
class="h-5 w-16 bg-transparent outline-none"
:class="{ 'focus:w-5/6': isInputFocused }"
type="text"
:placeholder="$t(i18nMap._global.search)"
:placeholder="$t('i18n._global.search')"
/>
</div>
</Transition>
Expand All @@ -42,7 +42,7 @@
>
<TooltipBase
class="invisible -mt-8"
:text="$t(i18nMap.components._global.slash_tooltip_label)"
:text="$t('i18n.components._global.slash_tooltip_label')"
/>
<p class="-mt-[0.075rem]">/</p>
</div>
Expand All @@ -52,7 +52,7 @@
>
<TooltipBase
class="invisible -mt-8"
:text="$t(i18nMap.components._global.command_tooltip_label)"
:text="$t('i18n.components._global.command_tooltip_label')"
/>
<p>⌘k</p>
</div>
Expand All @@ -62,7 +62,7 @@
>
<TooltipBase
class="invisible -mt-8"
:text="$t(i18nMap.components._global.control_tooltip_label)"
:text="$t('i18n.components._global.control_tooltip_label')"
/>
<p>⌃k</p>
</div>
Expand All @@ -82,14 +82,14 @@
size="1em"
/>
<label for="input-search" class="hidden md:block">{{
$t(i18nMap._global.search)
$t("i18n._global.search")
}}</label>
<input
id="input-search"
class="bg-transparent focus:outline-none"
:class="{ hidden: !expanded }"
type="text"
:placeholder="$t(i18nMap._global.search)"
:placeholder="$t('i18n._global.search')"
/>
<Icon v-if="expanded" class="absolute right-3" :name="IconMap.FILTER" />
</div>
Expand All @@ -99,7 +99,6 @@
import { useMagicKeys, whenever } from "@vueuse/core";
import { IconMap } from "~/types/icon-map";
import { SearchBarLocation } from "~/types/location";
import { i18nMap } from "~/types/i18n-map";

export interface Props {
location: SearchBarLocation;
Expand Down
8 changes: 2 additions & 6 deletions frontend/components/btn/BtnRoadMap.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,8 @@
id="btn-roadmap"
class="style-btn select-none items-center rounded-md px-3 py-[0.35rem] text-base font-semibold"
to="https://docs.activist.org/activist/product/about/roadmap"
:aria-label="$t(i18nMap.components.btn_road_map.aria_label)"
:aria-label="$t('i18n.components.btn_road_map.aria_label')"
>
{{ $t(i18nMap.components._global.roadmap) }}
{{ $t("i18n.components._global.roadmap") }}
</NuxtLink>
</template>

<script setup lang="ts">
import { i18nMap } from "~/types/i18n-map";
</script>
9 changes: 4 additions & 5 deletions frontend/components/btn/BtnShareIcon.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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(i18nMap.components.btn_share_icon.url_copied)"
:text="$t('i18n.components.btn_share_icon.url_copied')"
:iconSize="iconSize"
/>
</div>
Expand All @@ -58,7 +58,6 @@ import {
STwitter,
} from "vue-socials";
import { toast } from "vue-sonner";
import { i18nMap } from "~/types/i18n-map";
import { IconMap } from "~/types/icon-map";

const vueSocials: { [key: string]: Component } = {
Expand Down Expand Up @@ -110,9 +109,9 @@ const { t } = useI18n();
const contentCopied = ref(false);

const getCurrentI18n: { [key: string]: string } = {
signal: i18nMap.components.btn_share_icon.opening_signal,
matrix: i18nMap.components.btn_share_icon.opening_matrix,
instagram: i18nMap.components.btn_share_icon.opening_instagram,
signal: "i18n.components.btn_share_icon.opening_signal",
matrix: "i18n.components.btn_share_icon.opening_matrix",
instagram: "i18n.components.btn_share_icon.opening_instagram",
};

const copyToClipboardThenOpenUrl = async (
Expand Down
3 changes: 1 addition & 2 deletions frontend/components/card/CardConnect.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<div class="card-style px-5 py-5">
<div class="flex items-center gap-5">
<h3 class="responsive-h3 text-left font-display">
{{ $t(i18nMap.components._global.connect) }}
{{ $t("i18n.components._global.connect") }}
</h3>
<IconEdit
v-if="userIsSignedIn"
Expand Down Expand Up @@ -53,7 +53,6 @@ import type {
} from "~/types/communities/organization";
import type { SocialLink } from "~/types/content/social-link";
import type { Event, EventSocialLink } from "~/types/events/event";
import { i18nMap } from "~/types/i18n-map";
import { IconMap } from "~/types/icon-map";

const props = defineProps<{
Expand Down
Loading

0 comments on commit 369f97f

Please sign in to comment.