Skip to content

Commit

Permalink
basic localisation implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
tdjsnelling committed Mar 15, 2023
1 parent 0cb5368 commit c73d3ba
Show file tree
Hide file tree
Showing 4 changed files with 190 additions and 120 deletions.
33 changes: 28 additions & 5 deletions client/components/Navigation.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { UserPlus } from "@styled-icons/boxicons-regular/UserPlus";
import Box from "./Box";
import Text from "./Text";
import Button from "./Button";
import LocaleContext from "../utils/LocaleContext";

const NavLink = styled.a(({ theme, href, highlights = [], mt = 0 }) => {
const router = useRouter();
Expand Down Expand Up @@ -56,13 +57,28 @@ const NavLink = styled.a(({ theme, href, highlights = [], mt = 0 }) => {
});
});

const LocaleSelector = styled.select(() =>
css({
background: "none",
color: "text",
border: 0,
fontSize: 0,
fontFamily: "body",
cursor: "pointer",
p: 0,
})
);

const Navigation = ({ isMobile, menuIsOpen, setMenuIsOpen }) => {
const [cookies] = useCookies();
const [role, setRole] = useState("user");
const [isServer, setIsServer] = useState(true);

const theme = useContext(ThemeContext);

const { locale, setLocale, locales, getLocaleString } =
useContext(LocaleContext);

const { asPath } = useRouter();

const { username, token } = cookies;
Expand All @@ -73,7 +89,6 @@ const Navigation = ({ isMobile, menuIsOpen, setMenuIsOpen }) => {
SQ_API_URL,
SQ_ALLOW_REGISTER,
SQ_VERSION,
SQ_TORRENT_CATEGORIES,
},
} = getConfig();

Expand Down Expand Up @@ -234,15 +249,15 @@ const Navigation = ({ isMobile, menuIsOpen, setMenuIsOpen }) => {
<Box display="grid" gridAutoFlow="row" gridGap={0}>
<Link href="/login" passHref>
<NavLink>
<Text>Log in</Text>
<Text>{getLocaleString("logIn")}</Text>
<LogInCircle size={24} />
</NavLink>
</Link>
{(SQ_ALLOW_REGISTER === "open" ||
SQ_ALLOW_REGISTER === "invite") && (
<Link href="/register" passHref>
<NavLink>
<Text>Register</Text>
<Text>{getLocaleString("register")}</Text>
<UserPlus size={24} />
</NavLink>
</Link>
Expand Down Expand Up @@ -270,10 +285,18 @@ const Navigation = ({ isMobile, menuIsOpen, setMenuIsOpen }) => {
>
■ sqtracker
</a>{" "}
</Text>
<Text color="grey" fontSize={0}>
v{SQ_VERSION}
</Text>
<LocaleSelector
value={locale}
onChange={(e) => setLocale(e.target.value)}
>
{locales.map((l) => (
<option key={`locale-${l}`} value={l}>
{l.toUpperCase()}
</option>
))}
</LocaleSelector>
</Box>
</Box>
);
Expand Down
16 changes: 16 additions & 0 deletions client/locales.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"en": {
"poweredBy": "Powered by",
"logIn": "Log in",
"register": "Register",
"email": "Email",
"username": "Username",
"usernameRules": "Can only consist of letters, numbers, and “.”",
"password": "Password",
"resetPassword": "Reset password",
"newPassword": "New password"
},
"fr": {
"logIn": "Se connecter"
}
}
253 changes: 138 additions & 115 deletions client/pages/_app.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import Input from "../components/Input";
import { NotificationsProvider } from "../components/Notifications";
import Text from "../components/Text";
import LoadingContext from "../utils/LoadingContext";
import LocaleContext from "../utils/LocaleContext";
import locales from "../locales.json";

const getThemeColours = (themeName, customTheme = {}) => {
switch (themeName) {
Expand Down Expand Up @@ -151,13 +153,17 @@ const Loading = styled(LoaderAlt)`
animation: ${spin} 1s linear infinite;
`;

const getLocaleString = (locale) => (key) =>
locales[locale][key] ?? locales.en[key];

const SqTracker = ({ Component, pageProps, initialTheme }) => {
const [isMobile, setIsMobile] = useState(false);
const [menuIsOpen, setMenuIsOpen] = useState(false);
const [theme, setTheme] = useState(initialTheme || "light");
const [isServer, setIsServer] = useState(true);
const [loading, setLoading] = useState(false);
const [userStats, setUserStats] = useState();
const [locale, setLocale] = useState("en");

const router = useRouter();

Expand Down Expand Up @@ -206,6 +212,9 @@ const SqTracker = ({ Component, pageProps, initialTheme }) => {
});
}

const { locale: localeCookie } = cookies;
if (Object.keys(locales).includes(localeCookie)) setLocale(localeCookie);

Router.events.on("routeChangeStart", () => setLoading(true));
Router.events.on("routeChangeComplete", () => setLoading(false));
Router.events.on("routeChangeError", () => setLoading(false));
Expand Down Expand Up @@ -261,131 +270,145 @@ const SqTracker = ({ Component, pageProps, initialTheme }) => {
<ThemeProvider theme={appTheme}>
<GlobalStyle />
<LoadingContext.Provider value={{ loading, setLoading }}>
<NotificationsProvider>
<Navigation
isMobile={isMobile}
menuIsOpen={menuIsOpen}
setMenuIsOpen={setMenuIsOpen}
/>
<Box
width="100%"
height="60px"
bg="background"
borderBottom="1px solid"
borderColor="border"
position="fixed"
top={0}
zIndex={9}
>
<LocaleContext.Provider
value={{
locale,
setLocale: (l) => {
setLocale(l);
setCookie("locale", l, { path: "/" });
},
locales: Object.keys(locales),
getLocaleString: getLocaleString(locale),
}}
>
<NotificationsProvider>
<Navigation
isMobile={isMobile}
menuIsOpen={menuIsOpen}
setMenuIsOpen={setMenuIsOpen}
/>
<Box
display="flex"
alignItems="center"
justifyContent="space-between"
maxWidth="body"
width="100%"
height="60px"
ml={[
0,
`max(calc((100vw - ${appTheme.sizes.body}) / 2), 200px)`,
]}
px={[4, 5]}
bg="background"
borderBottom="1px solid"
borderColor="border"
position="fixed"
top={0}
zIndex={9}
>
<Box display="flex" alignItems="center">
<Button
onClick={() => setMenuIsOpen(true)}
variant="noBackground"
display={["block", "none"]}
px={1}
py={1}
mr={3}
>
<Menu size={24} />
</Button>
{loading && (
<Box mr={3}>
<Loading size={24} />
</Box>
)}
{SQ_SITE_WIDE_FREELEECH === true && (
<Text
icon={Bell}
iconColor="primary"
iconWrapperProps={{ justifyContent: "flex-end" }}
fontSize={[0, 2]}
>
Site-wide freeleech enabled!
</Text>
)}
</Box>
{!isServer && token && (
<Box
display="flex"
alignItems="center"
justifyContent="space-between"
maxWidth="body"
height="60px"
ml={[
0,
`max(calc((100vw - ${appTheme.sizes.body}) / 2), 200px)`,
]}
px={[4, 5]}
>
<Box display="flex" alignItems="center">
{userStats && (
<Box
display={["none", "flex"]}
alignItems="center"
color="grey"
>
<Sort size={14} />
<Text
color={
userStats.ratio !== -1 &&
userStats.ratio < SQ_MINIMUM_RATIO
? "error"
: "grey"
}
fontSize={0}
ml={1}
mr={2}
>
{userStats.ratio === -1 ? "N/A" : userStats.ratio}
</Text>
<CaretUp size={16} />
<Text fontSize={0} ml={0} mr={2}>
{prettyBytes(userStats.up ?? 0)}
</Text>
<CaretDown size={16} />
<Text fontSize={0} ml={0} mr={2}>
{prettyBytes(userStats.down ?? 0)}
</Text>
<Award size={16} />
<Text fontSize={0} ml={0} mr={4}>
{userStats.bp ?? 0} BP
</Text>
<Button
onClick={() => setMenuIsOpen(true)}
variant="noBackground"
display={["block", "none"]}
px={1}
py={1}
mr={3}
>
<Menu size={24} />
</Button>
{loading && (
<Box mr={3}>
<Loading size={24} />
</Box>
)}
<Box as="form" onSubmit={handleSearch}>
<Input
name="query"
placeholder="Search"
maxWidth="300px"
ref={searchRef}
/>
</Box>
{allowThemeToggle && (
<Button
variant="secondary"
onClick={() => {
setThemeAndSave(theme === "light" ? "dark" : "light");
}}
width="40px"
px={2}
py={2}
ml={3}
{SQ_SITE_WIDE_FREELEECH === true && (
<Text
icon={Bell}
iconColor="primary"
iconWrapperProps={{ justifyContent: "flex-end" }}
fontSize={[0, 2]}
>
{theme === "light" ? (
<Sun size={24} />
) : (
<Moon size={24} />
)}
</Button>
Site-wide freeleech enabled!
</Text>
)}
</Box>
)}
{!isServer && token && (
<Box display="flex" alignItems="center">
{userStats && (
<Box
display={["none", "flex"]}
alignItems="center"
color="grey"
>
<Sort size={14} />
<Text
color={
userStats.ratio !== -1 &&
userStats.ratio < SQ_MINIMUM_RATIO
? "error"
: "grey"
}
fontSize={0}
ml={1}
mr={2}
>
{userStats.ratio === -1 ? "N/A" : userStats.ratio}
</Text>
<CaretUp size={16} />
<Text fontSize={0} ml={0} mr={2}>
{prettyBytes(userStats.up ?? 0)}
</Text>
<CaretDown size={16} />
<Text fontSize={0} ml={0} mr={2}>
{prettyBytes(userStats.down ?? 0)}
</Text>
<Award size={16} />
<Text fontSize={0} ml={0} mr={4}>
{userStats.bp ?? 0} BP
</Text>
</Box>
)}
<Box as="form" onSubmit={handleSearch}>
<Input
name="query"
placeholder="Search"
maxWidth="300px"
ref={searchRef}
/>
</Box>
{allowThemeToggle && (
<Button
variant="secondary"
onClick={() => {
setThemeAndSave(
theme === "light" ? "dark" : "light"
);
}}
width="40px"
px={2}
py={2}
ml={3}
>
{theme === "light" ? (
<Sun size={24} />
) : (
<Moon size={24} />
)}
</Button>
)}
</Box>
)}
</Box>
</Box>
<Box as="main" mt="60px">
<Component {...pageProps} />
</Box>
</Box>
<Box as="main" mt="60px">
<Component {...pageProps} />
</Box>
</NotificationsProvider>
</NotificationsProvider>
</LocaleContext.Provider>
</LoadingContext.Provider>
</ThemeProvider>
</>
Expand Down
Loading

0 comments on commit c73d3ba

Please sign in to comment.