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

Release #504

Merged
merged 10 commits into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion components/EventTime/patterns/EventTimeShort/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import PropTypes from "prop-types";
import { makeDateObject, useGlobalData } from "@/lib/utils";
import * as Styled from "./styles";
import { fallbackLng } from "@/lib/i18n/settings";

function renderShortDate({ month, day, year }) {
return (
Expand All @@ -14,7 +15,7 @@ function renderShortDate({ month, day, year }) {

export default function EventTimeShort({ startDate, endDate, isSameDay }) {
const localeInfo = useGlobalData("localeInfo");
const lang = localeInfo?.language || "en-US";
const lang = localeInfo?.language || fallbackLng;
const endDateObject = makeDateObject(endDate, lang, true);
const startDateObject = !isSameDay
? makeDateObject(startDate, lang, true)
Expand Down
3 changes: 2 additions & 1 deletion components/content-blocks/Callout/CalloutEntry/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
import * as Styled from "./styles";
import { Image } from "@rubin-epo/epo-react-lib";
import { useRelease } from "@/lib/api/noirlabReleases";
import { fallbackLng } from "@/lib/i18n/settings";

const getDateString = (newsDate, eventStart, eventEnd, lang) => {
if (newsDate) {
Expand All @@ -32,7 +33,7 @@ const getDateString = (newsDate, eventStart, eventEnd, lang) => {
export default function CalloutEntry({ callout }) {
const { t } = useTranslation();
const localeInfo = useGlobalData("localeInfo");
const lang = localeInfo?.language || "en-US";
const lang = localeInfo?.language || fallbackLng;
const { id, entry, backgroundColor } = callout;
// mix in the noirlabReleases from additional fetch to different endpoint
const { data: entryWithRelease } = useRelease(getSiteString(lang), entry[0]);
Expand Down
3 changes: 2 additions & 1 deletion components/content-blocks/GridBlock/NewsGrid.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ import {
import { Grid } from "@rubin-epo/epo-react-lib";
import Tile from "@/atomic/Tile";
import Loader from "@/atomic/Loader";
import { fallbackLng } from "@/lib/i18n/settings";

const NewsGrid = ({ items = [], limit, listTypeId, sectionHandle, pageId }) => {
const { t } = useTranslation();
const localeInfo = useGlobalData("localeInfo");
const lang = localeInfo?.language || "en-US";
const lang = localeInfo?.language || fallbackLng;
// get manually-curated data first
let allItems = normalizeItemData(items);

Expand Down
3 changes: 2 additions & 1 deletion components/dynamic/NewsList/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
makeReleaseFeature,
useGlobalData,
} from "@/lib/utils";
import { fallbackLng } from "@/lib/i18n/settings";

const NewsList = ({
button,
Expand All @@ -22,7 +23,7 @@ const NewsList = ({
}) => {
const { t } = useTranslation();
const localeInfo = useGlobalData("localeInfo");
const lang = localeInfo?.language || "en-US";
const lang = localeInfo?.language || fallbackLng;
const cols = initialLimit === 4 ? 4 : initialLimit === 3 ? 3 : 2;
const canShowFeatured = initialLimit > 4;

Expand Down
3 changes: 2 additions & 1 deletion components/dynamic/SearchList/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { Grid } from "@rubin-epo/epo-react-lib";
import DataList from "@/dynamic/DataList";
import Tile from "@/atomic/Tile";
import * as Styled from "./styles";
import { fallbackLng } from "@/lib/i18n/settings";

const SearchList = ({
button,
Expand All @@ -24,7 +25,7 @@ const SearchList = ({
const { t } = useTranslation();
const localeInfo = useGlobalData("localeInfo");
const rootPages = useGlobalData("rootPages");
const lang = localeInfo?.language || "en-US";
const lang = localeInfo?.language || fallbackLng;

const makePretitle = (entry) => {
if (entry.eventType) {
Expand Down
82 changes: 43 additions & 39 deletions components/global/Header/LanguageSelect/index.js
Original file line number Diff line number Diff line change
@@ -1,75 +1,79 @@
import { useState, useEffect, useRef } from "react";
import PropTypes from "prop-types";
import { useRouter } from "next/router";
import { useEffect, useState } from "react";
import { useRouter, useSearchParams, usePathname } from "next/navigation";
import { useTranslation } from "react-i18next";
import { useGlobalData } from "@/lib/utils";
import { getCookie } from "cookies-next";
import { cookieName, fallbackLng } from "@/lib/i18n/settings";
import * as Styled from "./styles";

const CRAFT_HOMEPAGE_URI = "__home__";
const filterSearchParams = (searchParams) => {
const filteredParams = [];

searchParams.forEach((value, key) => {
if (key !== "locale" && key !== "uriSegments") {
filteredParams.push(`${key}=${value}`);
}
});

return `?${filteredParams.join("&")}`;
};

export default function LanguageSelect({ id }) {
const [isLoading, setLoading] = useState(false);
const router = useRouter();
const { t } = useTranslation();
const pathname = usePathname();
const searchParams = useSearchParams();
const {
localeInfo: { language: currentLanguage, localized },
} = useGlobalData();
const [toEs, setToEs] = useState(currentLanguage !== "en-US");
const [loading, setLoading] = useState(false);
const switchCount = useRef(0);

useEffect(() => {
// don't run effect for change to `toEs` on mount
if (switchCount.current > 0) {
const newLang = toEs ? "es" : "en-US";
const newRoute = getNewRoute(newLang);
if (!newRoute) return;
router.push(newRoute);
}
t,
i18n: { changeLanguage },
} = useTranslation();
const locale = getCookie(cookieName);

switchCount.current++;
}, [toEs]); // eslint-disable-line react-hooks/exhaustive-deps
const isDefaultLocale = fallbackLng.includes(locale);

useEffect(() => {
setLoading(false);
}, [currentLanguage]);

const getNewRoute = (newLanguage) => {
const newLocale = localized.find(
(locale) => locale.language === newLanguage
);
const uri = newLocale?.uri;
if (uri === CRAFT_HOMEPAGE_URI) return "/";
return uri;
};
}, [pathname]);

const handleClick = () => {
if (!loading) {
setToEs((prevValue) => !prevValue);
const newLocale = isDefaultLocale ? "es" : "en";

if (newLocale !== locale) {
const parts = pathname?.split("/") || [];
parts.shift();

if (locale !== fallbackLng) {
parts.shift();
}

const route = `/${newLocale}/${parts.join("/")}${filterSearchParams(
searchParams
)}`;
setLoading(true);
router.replace(route, { scroll: false });
changeLanguage(newLocale);
}
setLoading(true);
};

return (
<Styled.Fieldset>
<legend className="a-hidden">{t("localize-content")}</legend>
<Styled.Label htmlFor={id} $disabled={loading}>
<Styled.Label htmlFor={id} $disabled={isLoading}>
<Styled.MobileLabelText role="presentation">
{t("language-select-label")}
</Styled.MobileLabelText>
<span className="a-hidden">{t("espanol-site-name")}</span>
<Styled.Switch
id={id}
checked={toEs}
aria-disabled={loading}
checked={!isDefaultLocale}
onClick={handleClick}
aria-disabled={isLoading}
/>
</Styled.Label>
</Styled.Fieldset>
);
}

LanguageSelect.displayName = "Global.LanguageSelect";

LanguageSelect.propTypes = {
id: PropTypes.string.isRequired,
};
3 changes: 2 additions & 1 deletion components/widgets/CurrentData/patterns/Daylight/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ import { timezoneOffset } from "@/helpers";
import { timezone } from "@/lib/observatory";
import { useTranslation } from "react-i18next";
import ChartLegend from "@/components/charts/Legend";
import { fallbackLng } from "@/lib/i18n/settings";

const Daylight = ({ times = [], variant = "primary" }) => {
const {
t,
i18n: { language = "en-US" },
i18n: { language = fallbackLng },
} = useTranslation();

const offset = timezoneOffset(timezone);
Expand Down
20 changes: 20 additions & 0 deletions contexts/i18next.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
"use client";
import PropTypes from "prop-types";
import useClientTranslation from "@/lib/i18n/client";
import { fallbackLng } from "@/lib/i18n/settings";
import { I18nextProvider } from "react-i18next";

const I18NextClientProvider = ({ locale = fallbackLng, children }) => {
const { i18n } = useClientTranslation(locale);

return <I18nextProvider i18n={i18n}>{children}</I18nextProvider>;
};

I18NextClientProvider.displayName = "i18next.Provider";

I18NextClientProvider.propTypes = {
locale: PropTypes.string,
children: PropTypes.node,
};

export default I18NextClientProvider;
4 changes: 3 additions & 1 deletion helpers/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
export const capitalize = (string, locale = "en-US") => {
import { fallbackLng } from "@/lib/i18n/settings";

export const capitalize = (string, locale = fallbackLng) => {
if (typeof string !== "string") return "";
return string.charAt(0).toLocaleUpperCase(locale) + string.slice(1);
};
Expand Down
20 changes: 17 additions & 3 deletions lib/api/entries.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { glossaryTermFragment } from "@/lib/api/fragments/glossary-term";
import { studentPageFragment } from "./fragments/student-page";
import { educatorPageFragment } from "./fragments/educator-page";
import { investigationLandingPageFragment } from "./fragments/investigation-landing-page";
import { getLocaleString } from "../utils";

function dataListQueryify(fragment) {
return gql`
Expand Down Expand Up @@ -68,20 +69,23 @@ async function getData(ENV) {
) {
uri
level
siteHandle
}
homepage: entries(
site: "*"
section: ["homepage"]
type: ["not", "redirectPage"]
) {
uri
siteHandle
}
search: entries(
site: "*"
section: ["searchResults"]
type: ["not", "redirectPage"]
) {
uri
siteHandle
}
}
`;
Expand All @@ -96,6 +100,7 @@ async function getData(ENV) {
type: ["not", "redirectPage"]
) {
uri
siteHandle
}
}
`;
Expand All @@ -109,9 +114,18 @@ export async function getAllEntries() {
const data = await getData(ENV);
return data.entries
.filter(({ uri }) => uri != null)
.map(({ uri, sectionHandle }) => ({
params: { uriSegments: uri.split("/"), uri, sectionHandle },
}));
.map(({ uri, sectionHandle, siteHandle }) => {
const segments = uri.split("/");

return {
params: {
locale: getLocaleString(siteHandle),
uriSegments: segments,
uri,
sectionHandle,
},
};
});
}

export function useDataList({
Expand Down
26 changes: 0 additions & 26 deletions lib/i18n.js

This file was deleted.

46 changes: 46 additions & 0 deletions lib/i18n/client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import i18n from "i18next";
import { initReactI18next, useTranslation } from "react-i18next";
import LanguageDetector from "i18next-browser-languagedetector";
import {
defaultNS,
languages,
getOptions,
namespaces,
cookieName,
fallbackLng,
} from "./settings";
import { loadResources } from "./index";

const runsOnServerSide = typeof window === "undefined";

i18n
.use(initReactI18next) // passes i18n down to react-i18next
.use(LanguageDetector)
.use(loadResources)
.init({
...getOptions(),
ns: namespaces,
fallbackNS: namespaces,
lng: undefined, // let detect the language on client side
detection: {
excludeCacheFor: languages,
lookupCookie: cookieName,
order: ["htmlTag", "cookie", "navigator"],
},
preload: runsOnServerSide ? languages : [],
});

export default function useClientTranslation(
lng = fallbackLng,
ns = defaultNS,
options
) {
const instance = useTranslation(ns, options);
const { i18n } = instance;

if (runsOnServerSide && i18n.resolvedLanguage !== lng) {
i18n.changeLanguage(lng);
}

return instance;
}
Loading
Loading