Skip to content

Commit

Permalink
feat(i18n): issue #27 (#191)
Browse files Browse the repository at this point in the history
* checkpoint: issue with localeswitcher component

* fix: prettify code for pr

* fix: commit pr ready

* fix: redirects from pages to next config file

* fix: admin link on header component

* fix: redirects moved to _app

* fix: minor fixations

* fix: html lang switch

* fix: prettify for pr

* fix: automatic redirect to /it

* feat: Adds some translations & Salvatore Riccardi as community member

---------

Co-authored-by: Coluzzi Andrea <[email protected]>
  • Loading branch information
salvatorericcardi and coluzziandrea authored Apr 20, 2024
1 parent 5dc33c2 commit 1c7da39
Show file tree
Hide file tree
Showing 25 changed files with 418 additions and 56 deletions.
6 changes: 6 additions & 0 deletions _community/members/sriccardi.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
fullname: Salvatore Riccardi
bio: Developer
picture: sriccardi.jpg
linkedin: https://www.linkedin.com/in/salvatore-riccardi/
github: https://github.com/salvatorericcardi
9 changes: 9 additions & 0 deletions dictionaries/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"home": {
"nextEventsTitle": "Next Events",
"nextEventsSubtitle": "Save dates and don't make commitments for upcoming community events!",
"previousEventsTitle": "Previous Events",
"previousEventsSubtitle": "Too bad, these events have already taken place! Follow the page to stay updated on upcoming events.",
"andManyOthers": "...and many others!"
}
}
9 changes: 9 additions & 0 deletions dictionaries/it.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"home": {
"nextEventsTitle": "Prossimi Eventi",
"nextEventsSubtitle": "Fissa le date e non prendere impegni per i prossimi eventi della community!",
"previousEventsTitle": "Eventi Passati",
"previousEventsSubtitle": "Peccato, questi eventi si sono già svolti! Segui la pagina per rimanere aggiornato sui prossimi appuntamenti.",
"andManyOthers": "...e molti altri!"
}
}
6 changes: 6 additions & 0 deletions i18n.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const i18n = {
defaultLocale: "it",
locales: ["it", "en"],
} as const;

export type Locale = (typeof i18n)["locales"][number];
11 changes: 11 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 6 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"add-to-calendar-button-react": "^2.6.10",
"autoprefixer": "^10.4.19",
"firebase": "^10.11.0",
"flag-icons": "^7.2.1",
"gray-matter": "^4.0.3",
"image-size": "^1.1.1",
"luxon": "^3.4.4",
Expand All @@ -32,19 +33,19 @@
"zod": "^3.22.4"
},
"devDependencies": {
"@types/image-size": "^0.8.0",
"@typescript-eslint/eslint-plugin": "^5.59.6",
"@typescript-eslint/parser": "^5.59.6",
"@vitejs/plugin-basic-ssl": "^1.1.0",
"@vitejs/plugin-react": "^4.2.1",
"@headlessui/react": "^1.7.18",
"@heroicons/react": "^2.1.3",
"@tailwindcss/typography": "^0.5.12",
"@types/image-size": "^0.8.0",
"@types/luxon": "^3.4.2",
"@types/node": "^20.12.7",
"@types/react": "18.2.79",
"@types/react-dom": "18.2.22",
"@types/react-helmet": "^6.1.11",
"@typescript-eslint/eslint-plugin": "^5.59.6",
"@typescript-eslint/parser": "^5.59.6",
"@vitejs/plugin-basic-ssl": "^1.1.0",
"@vitejs/plugin-react": "^4.2.1",
"dotenv-cli": "^7.4.1",
"eslint": "8.57.0",
"eslint-config-prettier": "^9.1.0",
Expand Down
Binary file added public/assets/community/sriccardi.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 18 additions & 7 deletions src/components/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,30 @@ import { XMarkIcon, Bars3Icon } from '@heroicons/react/24/outline';
import navigationLinks from '@/model/navigation';
import React, { useMemo } from 'react';
import { usePathname } from 'next/navigation';
import { Locale } from 'i18n.config';
import LocaleSwitcher from './LocaleSwitcher';

function classNames(...classes: string[]): string {
return classes.filter(Boolean).join(' ');
}

const Header: React.FC = () => {
const Header = (props: { lang: Locale }) => {
const pathname = usePathname();
const links = useMemo(
() =>
navigationLinks.map(link => ({
...link,
current: link.href === pathname
})),
[pathname]
navigationLinks.map(link => {
if (link.name === 'Admin team') {
link.href = `/${props.lang}/admins/team`;
}

return {
...link,
current: link.href === pathname
};
}),
[pathname, props.lang]
);

return (
<Disclosure as='nav'>
{({ open: isOpen }) => (
Expand All @@ -48,7 +57,7 @@ const Header: React.FC = () => {

<div className='flex w-full flex-1 items-center justify-center lg:items-stretch lg:justify-between'>
<div className='flex flex-shrink-0 items-center'>
<Link href='/'>
<Link href={`/${props.lang}`}>
<Image
src={logoLight}
alt='Logo LiT'
Expand All @@ -68,6 +77,7 @@ const Header: React.FC = () => {
</Link>
</div>
<div className='hidden items-center sm:ml-6 lg:flex'>
<LocaleSwitcher lang={props.lang} mobile={false} />
<div className='flex space-x-4'>
{links.map(item => (
<Link
Expand All @@ -93,6 +103,7 @@ const Header: React.FC = () => {

<Disclosure.Panel className='lg:hidden'>
<div className='space-y-1 px-2 pt-2 pb-3'>
<LocaleSwitcher lang={props.lang} mobile={true} />
{links.map(item => (
<Disclosure.Button
as={Link}
Expand Down
5 changes: 4 additions & 1 deletion src/components/LeaveFeedback.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import Link from 'next/link';
import React from 'react';
import { ChatBubbleLeftRightIcon } from '@heroicons/react/24/outline';
import { useRouter } from 'next/router';

export const LeaveFeedback = () => {
const router = useRouter();

return (
<div className='text-center'>
<h2 className='text-3xl font-bold text-gray-900 dark:text-slate-200 sm:text-4xl'>
Expand All @@ -13,7 +16,7 @@ export const LeaveFeedback = () => {
</p>
<div className={'mx-auto mt-6 flex justify-center'}>
<Link
href='/feedback/new'
href={`${router.query.lang}/feedback/new`}
className='flex items-center justify-between gap-2 rounded-md border border-transparent bg-primary bg-opacity-80 px-4 py-3 text-base font-medium text-white shadow-sm backdrop-blur-sm hover:bg-primary-dark sm:px-8'
>
Lascia un Feedback! <ChatBubbleLeftRightIcon className='h-6 w-6' />
Expand Down
62 changes: 62 additions & 0 deletions src/components/LocaleSwitcher.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
'use client';
import 'flag-icons';
import { MouseEvent, useState } from 'react';
import { useRouter } from 'next/router';
import { Locale, i18n } from 'i18n.config';
import { usePathname } from 'next/navigation';

export default function LocaleSwitcher(props: {
lang: Locale;
mobile: boolean;
}) {
const router = useRouter();
const pathname = usePathname();

const defaultLocale = i18n.defaultLocale;
const [animation, setAnimation] = useState('');
const [locale, setLocale] = useState(props.lang);

const toggle = (e: MouseEvent<HTMLDivElement>) => {
const container = e.target as HTMLDivElement;
const changeLocale = i18n.locales.filter(
locale => locale !== props.lang
)[0];

setLocale(changeLocale);
setAnimation(props.lang === defaultLocale ? 'slide-out' : 'slide-in');

container.onanimationend = () => {
const regex = /it|en/;

if (regex.test(pathname)) {
void router.replace(pathname.replace(regex, changeLocale));
} else {
void router.replace(`/${changeLocale}${pathname}`);
}
};
};

return (
<div
className={`${props.mobile ? 'flex flex-row px-3 py-2' : 'hidden p-4 items-center lg:flex lg:flex-row'} gap-x-1`}
>
<span
className='fi fi-it'
style={{ display: 'block', width: '32px', height: '16px' }}
></span>
<div
className='cursor-pointer w-8 h-4 rounded'
style={{ backgroundColor: 'rgb(71 85 105 / 1)' }}
onClick={e => toggle(e)}
>
<div
className={`bg-white w-1/2 h-full rounded-full ${locale} ${animation}`}
/>
</div>
<span
className='fi fi-gb'
style={{ display: 'block', width: '32px', height: '16px' }}
></span>
</div>
);
}
5 changes: 4 additions & 1 deletion src/components/event/EventWidget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@ import React, { useCallback, useMemo } from 'react';
import EventActions from './EventActions';
import EventDescription from './EventDescription';
import EventTags from './EventTags';
import { useRouter } from 'next/router';

const thumbHeight = 400;
type Props = {
event: IEvent;
};

const EventWidget: React.FC<Props> = ({ event }: Props) => {
const router = useRouter();

const renderEventImage = useCallback(() => {
if (event.thumbnail) {
return (
Expand Down Expand Up @@ -40,7 +43,7 @@ const EventWidget: React.FC<Props> = ({ event }: Props) => {
}, [isPast]);

return (
<Link href={`/events/${event.slug}`} legacyBehavior>
<Link href={`${router.query.lang}/events/${event.slug}`} legacyBehavior>
<div className={getEventWidgetClasses()}>
{renderEventImage()}
<div className='flex flex-1 flex-col gap-2 p-4'>
Expand Down
39 changes: 39 additions & 0 deletions src/globals.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
.en {
position: relative;
left: calc(100% - 16px);
}

.it {
position: relative;
left: 0;
}

.slide-in {
animation-name: slidein;
animation-duration: 750ms;
}

.slide-out {
animation-name: slideout;
animation-duration: 750ms;
}

@keyframes slideout {
from {
left: 0%;
}

to {
left: calc(100% - 16px);
}
}

@keyframes slidein {
from {
left: calc(100% - 16px);
}

to {
left: 0%;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import {
BsTwitter,
BsFillHouseDoorFill
} from 'react-icons/bs';
import { i18n } from 'i18n.config';
import { useRouter } from 'next/router';

type Admin = {
name: string;
Expand Down Expand Up @@ -138,9 +140,14 @@ const AdminCard: React.FC<Admin> = ({
};

const AdminTeam = () => {
const router = useRouter();
const locale = i18n.locales.filter(
locale => router?.query.lang === locale
)[0];

return (
<div>
<Header />
<Header lang={locale} />
<div className='flex justify-center items-center'>
<div className='w-[100%] md:w-fit p-4 m-4 justify-center rounded-md shadow-md bg-slate-200 dark:bg-slate-800'>
<div className='flex flex-col items-center justify-center space-y-5 mb-4 sm:space-y-4 md:max-w-xl lg:max-w-3xl xl:max-w-none'>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
import { getAllCommunityMembers } from '@/utils/community';
import { isDevEnv } from '@/utils/dev';
import CommunityMember from '@/components/CommunityMember';
import { getAllLocales } from '@/utils/locale';

/**
* display the list of community members
Expand Down Expand Up @@ -87,6 +88,21 @@ const CommunityMemberList: React.FC<
);
};

export const getStaticPaths = async () => {
const locales = getAllLocales();

return {
paths: locales.map(locale => {
return {
params: {
lang: locale
}
};
}),
fallback: false
};
};

export const getStaticProps = (() => ({
props: { members: getAllCommunityMembers() }
})) satisfies GetStaticProps<{
Expand Down
Loading

0 comments on commit 1c7da39

Please sign in to comment.