Skip to content

Commit

Permalink
Merge pull request #200 from sinamics/auto_detect_lang
Browse files Browse the repository at this point in the history
Autodetect language
  • Loading branch information
sinamics committed Nov 8, 2023
2 parents 379344e + 95b7972 commit 682681a
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 11 deletions.
5 changes: 3 additions & 2 deletions next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ const config = {
* @see https://github.com/vercel/next.js/issues/41980
*/
i18n: {
defaultLocale: "en",
locales: ["en", "no", "zh", "es"],
defaultLocale: "default",
locales: ["default", "en", "no", "zh", "es"],
},
trailingSlash: true,
images: {
domains: ["pbs.twimg.com"],
},
Expand Down
1 change: 1 addition & 0 deletions src/locales/lang.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const supportedLocales = ["en", "no", "zh", "es"];
51 changes: 50 additions & 1 deletion src/middleware.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,51 @@
export { default } from "next-auth/middleware";
import { NextRequest, NextResponse } from "next/server";
import { supportedLocales } from "./locales/lang";
export const config = { matcher: ["/dashboard", "/networks"] };

const PUBLIC_FILE = /\.(.*)$/;

export async function middleware(req: NextRequest) {
if (
req.nextUrl.pathname.startsWith("/_next") ||
req.nextUrl.pathname.includes("/api/") ||
PUBLIC_FILE.test(req.nextUrl.pathname)
) {
return;
}

// Handle automatic locale detection
if (req.nextUrl.locale === "default") {
const fallbackLocale = "en";
const acceptLanguageHeader = req.headers.get("accept-language");
let preferredLocale = fallbackLocale;

if (acceptLanguageHeader) {
// Parse the Accept-Language header and sort by quality score
const locales = acceptLanguageHeader
.split(",")
.map((lang) => {
const [locale, qValue] = lang.trim().split(";q=");
return {
locale: locale.split("-")[0],
quality: qValue ? parseFloat(qValue) : 1,
};
})
.sort((a, b) => b.quality - a.quality); // Sort based on quality values
// Select the first supported locale with the highest quality score
const matchedLocale = locales.find((l) => supportedLocales.includes(l.locale));
if (matchedLocale) {
preferredLocale = matchedLocale.locale;
}
}

// Redirect to the preferred locale if it's different from the current one
if (preferredLocale !== req.nextUrl.locale) {
return NextResponse.redirect(
new URL(
`/${preferredLocale}${req.nextUrl.pathname}${req.nextUrl.search}`,
req.url,
),
);
}
}
}
1 change: 0 additions & 1 deletion src/pages/_app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ const App: AppType<{ session: Session | null }> = ({
if (storedLocale && storedLocale !== locale) {
void push(asPath, asPath, { locale: storedLocale });
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

useEffect(() => {
Expand Down
6 changes: 3 additions & 3 deletions src/pages/auth/login/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ export const getServerSideProps: GetServerSideProps<Props> = async (
context: GetServerSidePropsContext,
) => {
const session = await getSession(context);
const messages = (await import(`~/locales/${context.locale}/common.json`)).default;
// const messages = (await import(`~/locales/${context.locale}/common.json`)).default;

if (!session || !("user" in session)) {
return { props: { messages } };
return { props: {} };
}

if (session.user) {
Expand All @@ -54,7 +54,7 @@ export const getServerSideProps: GetServerSideProps<Props> = async (
}

return {
props: { auth: session.user, messages },
props: { auth: session.user },
};
};

Expand Down
4 changes: 2 additions & 2 deletions src/pages/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export const getServerSideProps: GetServerSideProps<Props> = async (
context: GetServerSidePropsContext,
) => {
const session = await getSession(context);
const messages = (await import(`~/locales/${context.locale}/common.json`)).default;
// const messages = (await import(`~/locales/${context.locale}/common.json`)).default;

if (session && "user" in session && session?.user) {
return {
Expand All @@ -25,7 +25,7 @@ export const getServerSideProps: GetServerSideProps<Props> = async (
destination: "/auth/login",
permanent: false,
},
props: { messages },
// props: { messages },
};
};
// No component is needed as we redirect
Expand Down
20 changes: 18 additions & 2 deletions src/pages/user-settings/account/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,16 @@ import { useTranslations } from "next-intl";
import { globalSiteVersion } from "~/utils/global";
import Link from "next/link";
import ApiToken from "~/components/userSettings/apiToken";
import { supportedLocales } from "~/locales/lang";

const languageNames = {
default: "System",
en: "English",
no: "Norwegian",
zh: "Chinese",
es: "Spanish",
};
const defaultLocale = "en";

const Account = () => {
const { asPath, locale, locales, push } = useRouter();
Expand All @@ -32,9 +35,22 @@ const Account = () => {
});

const ChangeLanguage = async (locale: string) => {
await push(asPath, asPath, { locale });
localStorage.setItem("ztnet-language", locale);
if (locale === "default") {
localStorage.removeItem("ztnet-language"); // Remove the local storage value for 'default' selection

// Detect the browser locale and fallback to the defaultLocale if it's not supported
const browserLocale = navigator.language.split("-")[0];
const isLocaleSupported = supportedLocales.includes(browserLocale);

await push(asPath, asPath, {
locale: isLocaleSupported ? browserLocale : defaultLocale,
});
} else {
localStorage.setItem("ztnet-language", locale); // Save the selected locale in local storage
await push(asPath, asPath, { locale }); // Navigate to the current path with the new locale
}
};

if (userError) {
toast.error(userError.message);
}
Expand Down

0 comments on commit 682681a

Please sign in to comment.