Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add translation hooks and packages #1980

Merged
merged 14 commits into from
Aug 2, 2023
Merged
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module.exports = {
"browser": true,
"es6": true,
},
"extends": ["eslint:recommended", "plugin:react/recommended" , "plugin:cypress/recommended"],
"extends": ["eslint:recommended", "plugin:react/recommended", "plugin:cypress/recommended"],
"globals": {
"Atomics": "readonly",
"SharedArrayBuffer": "readonly",
Expand Down
15 changes: 11 additions & 4 deletions components/Hero.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,26 @@ import Heading from './typography/Heading'
import Paragraph from './typography/Paragraph'
import AlgoliaSearch, { SearchButton } from './AlgoliaSearch'; // Import AlgoliaSearch component
import IconLoupe from './icons/Loupe';
import {
getAllLanguageSlugs,
getLanguage,
useTranslation,
} from "next-i18next-static-site";
anshgoyalevil marked this conversation as resolved.
Show resolved Hide resolved

export default function Hero({ className = ''}) {

const { t } = useTranslation();

return (
<>
<AnnouncementHero className='my-4' />
<header className={`px-2 mt-12 ${className}`}>
<div className="text-center">
<Heading level="h1" typeStyle="heading-xl" className="mb-4">
Building the future of {` `}
{t('landingPageHeroHeading_1')} {` `}
<span className="block md:-mt-4">
{" "}
Event-Driven Architectures (EDA)
{t('landingPageHeroHeading_2')}
</span>
</Heading>
<Heading level="h2" typeStyle="body-lg" textColor="text-gray-700" className="mb-10 max-w-4xl mx-auto">
Expand Down Expand Up @@ -69,5 +77,4 @@ export default function Hero({ className = ''}) {
</header>
</>
);
}

}
2 changes: 1 addition & 1 deletion components/buttons/GithubButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Button from './Button'
import IconGithub from '../icons/Github'

export default function GithubButton({
text = 'View on Github',
text = 'Github',
anshgoyalevil marked this conversation as resolved.
Show resolved Hide resolved
href = 'https://github.com/asyncapi',
target = '_blank',
iconPosition = 'left',
Expand Down
21 changes: 21 additions & 0 deletions components/languageSelector/LanguageSelect.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { twMerge } from 'tailwind-merge'
export default function LanguageSelect({
className = '',
onChange = () => { },
options = [],
selected,
}) {
return (
<select data-testid="Select-form"
onChange={(ev) => onChange(ev.target.value)}
className={twMerge(`form-select h-full py-0 px-3 pr-7 inline-flex justify-center rounded-md border border-gray-300 shadow-sm py-2 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-offset-gray-100 focus:ring-indigo-500 ${className}`)}
value={selected}
>
{options.map((option, index) => (
<option key={index} selected={option.value === selected} value={option.value} data-testid="Option-form">
{option.text}
</option>
))}
</select>
)
}
48 changes: 48 additions & 0 deletions components/link.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import Link from "next/link";
import { useRouter } from "next/router";
import { defaultLanguage, languages } from "next-i18next-static-site";

const LinkComponent = ({ children, locale, ...props }) => {
const router = useRouter();
const { pathname, query, asPath } = router;

// Detect current language
const slug = asPath.split("/")[1];
const langSlug = languages.includes(slug) && slug;
const language = query.lang || langSlug || defaultLanguage;

let href = props.href || pathname;

if (locale) {
if (props.href) {
href = `/${locale}${href}`;
} else {
if (pathname.startsWith("/404")) {
href = `/${locale}`;
} else {
href = pathname.replace("[lang]", locale);
}
}
} else {
if (language) {
href = `/${language}${href}`;
} else {
href = `/${href}`;
}
}

// Fix double slashes
href = href.replace(/([^:]\/)\/+/g, "$1").replace("//", "/");

return (
<Link href={href} passHref>
{children}
</Link>
);
};

export const LinkText = ({ href, children, ...props }) => {
return <Link href={href || ""}>{children}</Link>;
};

export default LinkComponent;
63 changes: 58 additions & 5 deletions components/navigation/NavBar.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,57 @@ import GithubButton from "../buttons/GithubButton"
import { SearchButton } from '../AlgoliaSearch';
import IconLoupe from '../icons/Loupe';
import Link from 'next/link';
import LanguageSelect from '../languageSelector/LanguageSelect';
import {
defaultLanguage,
languages,
useTranslation,
} from "next-i18next-static-site";

const isMobile = isMobileDevice();
const uniqueLangs = [...new Set(["EN", "DE"])].map((repo) => ({
key: repo,
text: repo,
}));

export default function NavBar({
className = '',
hideLogo = false,
}) {
const { asPath } = useRouter();
const router = useRouter();
const { pathname, query, asPath } = router;
const [open, setOpen] = useState();
const [mobileMenuOpen, setMobileMenuOpen] = useState();
const [lang, setLang] = useState("en");
const { i18n } = useTranslation();

const changeLanguage = async (locale) => {
// Detect current language
const slug = asPath.split("/")[1];
const langSlug = languages.includes(slug) && slug;
const language = query.lang || langSlug || defaultLanguage;

let href = pathname;

if (locale) {
if (pathname.startsWith("/404")) {
href = `/${locale}`;
} else {
href = pathname.replace("[lang]", locale);
}
} else {
if (language) {
href = `/${language}${href}`;
} else {
href = `/${href}`;
}
}

// Fix double slashes
href = href.replace(/([^:]\/)\/+/g, "$1").replace("//", "/");

router.push(href);
};

function outsideClick(menu) {
if (open !== menu) return;
Expand Down Expand Up @@ -107,9 +148,9 @@ export default function NavBar({
<div className="relative" onMouseLeave={() => showMenu(null)} ref={communityRef}>
<NavItem
text="Community"
href="/community"
onClick={() => showOnClickMenu('community')}
onMouseEnter={() => showMenu('community')}
href="/community"
onClick={() => showOnClickMenu('community')}
onMouseEnter={() => showMenu('community')}
hasDropdown
/>
{open === 'community' && <CommunityPanel />}
Expand All @@ -127,7 +168,19 @@ export default function NavBar({
<IconLoupe />
</SearchButton>

<GithubButton text="Star on GitHub" href="https://github.com/asyncapi/spec" className="py-2 ml-2" inNav="true" />
<LanguageSelect
options={uniqueLangs}
onChange={(value) => {
setLang(value.toLowerCase());
changeLanguage(value.toLowerCase());
}}
className=""
selected={i18n.language.toLocaleUpperCase()}
/>
anshgoyalevil marked this conversation as resolved.
Show resolved Hide resolved

<GithubButton text="GitHub" href="https://github.com/asyncapi/spec" className="py-2 ml-2" inNav="true" />


anshgoyalevil marked this conversation as resolved.
Show resolved Hide resolved
</div>
</nav>

Expand Down
18 changes: 18 additions & 0 deletions lib/locales.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { languages, namespaces } from "next-i18next-static-site";

// Load all locales, required for next-i18n-static-site
// Can be changed based on your folder structure
const locales = {};
languages.map((language) => {
locales[language] = {};

namespaces.map((namespace) => {
locales[language][namespace] = require("./../locales/" +
language +
"/" +
namespace +
".json");
});
});
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kindly wrap this in a function and then return the required response from the function.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually, this is not my implementation. It is suggested by the plugin author since were in need to use the static site built due to Netlify restrictions.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you please share the source you are following to create this file?

IMHO, even if we have to implement such logic, I don't think it will make any difference while implementing it inside functions. Reason why I'm asking for making it as a function is that we should work on code quality as well, instead of just writing it as plain implementation of js. Also, it will be easier to add unit tests (later on) for this file.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done! I totally agree with your points.

I am following this package. Their one of the examples is what I tried imitating in our project.

The reason to use this package is that previously I was using the next-i18next package to handle the translation-related logic, and everything was going smoothly inside the local dev. environment.
As I pushed that code, it became useless because Netlify cannot process translations on the server, and need pre-generated translations.
Another option was to use a Node.JS environment to host the website, but that doesn't seem viable.


export default locales;
4 changes: 4 additions & 0 deletions locales/de/common.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"landingPageHeroHeading_1": "Die Zukunft gestalten",
"landingPageHeroHeading_2": "Ereignisgesteuerte Architekturen (EDA)"
}
4 changes: 4 additions & 0 deletions locales/en/common.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"landingPageHeroHeading_1": "Building the future of",
"landingPageHeroHeading_2": "Event-Driven Architectures (EDA)"
}
anshgoyalevil marked this conversation as resolved.
Show resolved Hide resolved
8 changes: 8 additions & 0 deletions next-i18next-static-site-config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module.exports = {
anshgoyalevil marked this conversation as resolved.
Show resolved Hide resolved
i18n: {
languages: ["en", "de"],
defaultLanguage: "en",
namespaces: ["common"],
defaultNamespace: "common",
},
};
27 changes: 17 additions & 10 deletions next.config.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
const frontmatter = require('remark-frontmatter')
const images = require('remark-images')
const gemoji = require('remark-gemoji-to-emoji')
const a11yEmoji = require('@fec/remark-a11y-emoji')
const slug = require('remark-slug')
const headingId = require('remark-heading-id')
const frontmatter = require('remark-frontmatter');
const images = require('remark-images');
const gemoji = require('remark-gemoji-to-emoji');
const a11yEmoji = require('@fec/remark-a11y-emoji');
const slug = require('remark-slug');
const headingId = require('remark-heading-id');
const { i18n } = require("./next-i18next-static-site-config");

const withMDX = require('@next/mdx')({
extension: /\.mdx?$/,
Expand All @@ -18,8 +19,11 @@ const withMDX = require('@next/mdx')({
],
rehypePlugins: [],
},
})
module.exports = withMDX({
});

const withTM = require("next-transpile-modules")(["next-i18next-static-site"]);

anshgoyalevil marked this conversation as resolved.
Show resolved Hide resolved
module.exports = withTM(withMDX({
pageExtensions: ['js', 'md'],
eslint: {
ignoreDuringBuilds: true,
Expand All @@ -33,6 +37,9 @@ module.exports = withMDX({
// config.resolve.alias["react/jsx-dev-runtime"] = require.resolve('react/jsx-dev-runtime');
// config.resolve.alias["react/jsx-runtime"] = require.resolve('react/jsx-runtime');

return config
return config;
},
publicRuntimeConfig: {
i18n,
},
})
}));
Loading
Loading