-
Notifications
You must be signed in to change notification settings - Fork 0
feat: internationalization #38
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
base: main
Are you sure you want to change the base?
Changes from all commits
3e3a9c5
c1cf8e7
96edc81
c1aff53
c9ee2d3
57940b3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
|
@@ -4,6 +4,7 @@ import "./globals.css"; | |||||||||
import { ReactQueryDevtools } from "@tanstack/react-query-devtools"; | ||||||||||
import ReactQueryProvider from "@/providers/react-query"; | ||||||||||
import clsx from "clsx"; | ||||||||||
import { DictionaryProvider } from "@/contexts/dictionary-provider"; | ||||||||||
|
||||||||||
const jamjuree = Bai_Jamjuree({ | ||||||||||
subsets: ["latin"], | ||||||||||
|
@@ -27,8 +28,10 @@ export default function RootLayout({ | |||||||||
<html className="h-full" lang="en"> | ||||||||||
<body className={clsx(jamjuree.variable, "font-jamjuree h-full")}> | ||||||||||
<ReactQueryProvider> | ||||||||||
{children} | ||||||||||
<ReactQueryDevtools initialIsOpen={false} /> | ||||||||||
<DictionaryProvider> | ||||||||||
{children} | ||||||||||
<ReactQueryDevtools initialIsOpen={false} /> | ||||||||||
</DictionaryProvider> | ||||||||||
Comment on lines
+33
to
+34
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We can move this out of the dictionary provider since it will never use it.
Suggested change
|
||||||||||
</ReactQueryProvider> | ||||||||||
</body> | ||||||||||
</html> | ||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should move this provider into the |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
"use client"; | ||
|
||
import { createContext, useContext, useEffect, useState } from "react"; | ||
import type { Dictionary, Language } from "@/internationalization/dictionaries"; | ||
import { getDictionary } from "@/internationalization/dictionaries"; | ||
import { api } from "@/lib/api"; | ||
import { useGetUserInfo } from "@/lib/queries/session"; | ||
|
||
export type DictionaryLanguage = Language; | ||
|
||
interface DictionaryContextData { | ||
dictionary: Dictionary; | ||
language: DictionaryLanguage; | ||
setLanguage?: (language: DictionaryLanguage) => void; | ||
} | ||
|
||
const DictionaryContext = createContext<DictionaryContextData | undefined>( | ||
undefined, | ||
); | ||
|
||
export async function PreferedLanguage(): Promise<DictionaryLanguage> { | ||
const response = await api.get("/auth/preferences/language"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could create a export function useGetUserPreference(preference: string) {
return useQuery({
queryKey: ["user", "preferences", preference],
queryFn: () => {} // function that does the fetching and that receives 'preference' as argument
})
} This way, we can benefit from all the tanstack cool perks and have a centralized way of getting any preference. |
||
console.log(response); | ||
if (!response) { | ||
throw new Error("Failed to fetch preferred language"); | ||
} | ||
const { language } = response.data; | ||
|
||
return language as DictionaryLanguage; | ||
} | ||
|
||
export function getBrowserLanguage(): DictionaryLanguage { | ||
if (typeof navigator !== "undefined" && navigator.language) { | ||
return navigator.language as DictionaryLanguage; | ||
} | ||
return "en-US"; | ||
} | ||
|
||
export function DictionaryProvider({ | ||
children, | ||
language: propLanguage, | ||
}: { | ||
children: React.ReactNode; | ||
language?: DictionaryLanguage; | ||
}) { | ||
const [language, setLanguage] = useState<DictionaryLanguage>( | ||
propLanguage || "en-US", | ||
); | ||
|
||
const user = useGetUserInfo(); | ||
|
||
useEffect(() => { | ||
if (!propLanguage) { | ||
(async () => { | ||
try { | ||
if (user) { | ||
const preferredLanguage = await PreferedLanguage(); | ||
setLanguage(preferredLanguage); | ||
} else { | ||
setLanguage(getBrowserLanguage()); | ||
} | ||
} catch { | ||
setLanguage("en-US"); | ||
} | ||
})(); | ||
} | ||
}, [propLanguage, user]); | ||
|
||
const dictionary = getDictionary(language); | ||
return ( | ||
<DictionaryContext.Provider value={{ dictionary, language, setLanguage }}> | ||
{children} | ||
</DictionaryContext.Provider> | ||
); | ||
} | ||
|
||
export function useDictionary() { | ||
const context = useContext(DictionaryContext); | ||
if (!context) { | ||
throw new Error("useDictionary must be used within a DictionaryProvider"); | ||
} | ||
return context.dictionary; | ||
} | ||
|
||
export function useLanguage() { | ||
const context = useContext(DictionaryContext); | ||
if (!context) { | ||
throw new Error("useLanguage must be used within a DictionaryProvider"); | ||
} | ||
return context.language; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import en from "./dictionaries/en.json"; | ||
import pt from "./dictionaries/pt.json"; | ||
|
||
const dictionaries = { | ||
"en-US": en, | ||
"en-GB": en, | ||
"en-CA": en, | ||
"pt-PT": pt, | ||
"pt-BR": pt, | ||
}; | ||
|
||
export type Language = keyof typeof dictionaries; | ||
export type Dictionary = (typeof dictionaries)[Language]; | ||
|
||
export const getDictionary = (lang: Language): Dictionary => { | ||
return dictionaries[lang] || dictionaries["en-US"]; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"greeting": "Hello" | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"greeting": "Olá" | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should change
lang="en"
according to the current language preference. Check out this example: https://github.com/cesium/hydrogen/blob/develop/src/app/%5Blang%5D/layout.tsx