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

Translate main pages #984

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
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
9 changes: 7 additions & 2 deletions frontend/src/components/Admonition.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import React from "react";
import { useRouter } from 'next/router';
const translateText = require('src/components/translates/Translate');

type AdType = {
ifmClass: string;
Expand Down Expand Up @@ -110,17 +112,20 @@ type Props = {
const Admonition = ({ type, title, children }: Props) => {
const adtype = types[type];

const router = useRouter();
const locale = router?.locale || "en"; // Use optional chaining to prevent accessing properties on null

return (
<div className={`admonition admonition-${type} alert alert--success`}>
<div className="admonition-heading">
<h5>
<span className="admonition-icon">{adtype.svg}</span>
{adtype.keyword} {title}
{translateText(locale, "Docs", adtype.keyword)} : {title}
</h5>
</div>
<div className="admonition-content">{children}</div>
</div>
);
};

export default Admonition;
export default Admonition;
8 changes: 7 additions & 1 deletion frontend/src/components/Search.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import { Hit, SearchResults } from "src/types/_generated_SearchResult";

const noExtension = (path: string) => path.replace(".md", "");

import { useRouter } from 'next/router';
const translateText = require('src/components/translates/Translate');

const Search: FC = () => {
const searchRef = useRef<HTMLDivElement>(null);
const [query, setQuery] = useState("");
Expand Down Expand Up @@ -40,6 +43,9 @@ const Search: FC = () => {
setActive(true);
window.addEventListener("click", onClick);
}, [onClick]);

const router = useRouter();
const locale = router?.locale || "en";

return (
<>
Expand All @@ -48,7 +54,7 @@ const Search: FC = () => {
className="search"
onChange={onChange}
onFocus={onFocus}
placeholder="Search..."
placeholder={translateText(locale, "Docs", "Search...")}
type="text"
value={query}
/>
Expand Down
7 changes: 6 additions & 1 deletion frontend/src/components/forum/BackLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,21 @@ import { Link } from "@chakra-ui/layout";
import NextLink from "next/link";
import { FC } from "react";

const translateText = require('src/components/translates/Translate');
import { useRouter } from 'next/router';

type Props = {
to: string;
};

const BackLink: FC<Props> = ({ to }) => {
const router = useRouter();
const locale = router.locale || 'en';
return (
<NextLink href={to}>
<Link className="black-80 hover-blue">
<Button leftIcon={<ArrowBackIcon />} variant="outline">
Back
{translateText(locale, "General", "Back")}
</Button>
</Link>
</NextLink>
Expand Down
43 changes: 27 additions & 16 deletions frontend/src/components/listing/ServerRow.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,23 +17,31 @@ import { useIsAdmin } from "src/auth/hooks";
import { useDeleteServer } from "src/components/listing/hooks";
import { Essential } from "src/types/_generated_Server";

const translateText = require('src/components/translates/Translate');
import { useRouter } from 'next/router';

type CopyBadgeProps = { text: string };
const CopyBadge: FC<CopyBadgeProps> = ({ text }) => {
const { onCopy, hasCopied } = useClipboard(text);

const router = useRouter();
const locale = router.locale || 'en';

return (
<HStack>
<Text fontSize="xl" fontWeight="bold" marginTop="0">
{text}
</Text>
<Button
size="xs"
onClick={onCopy}
style={hasCopied ? { backgroundColor: "#81C784", color: "white" } : {}}
>
{hasCopied ? "COPIED" : "COPY"}
</Button>
</HStack>
);
<HStack>
<Text fontSize="xl" fontWeight="bold" marginTop="0">
{text}
</Text>
<Button
size="xs"
onClick={onCopy}
style={hasCopied ? { backgroundColor: "#81C784", color: "white" } : {}}
>
{hasCopied ? translateText(locale, "Servers", "COPIED") : translateText(locale, "Servers", "COPY")}
</Button>
</HStack>
);

};

type ServerRowProps = { server: Essential };
Expand All @@ -45,6 +53,9 @@ const ServerRow: FC<ServerRowProps & ChakraProps> = ({ server, sx }) => {
);
const admin = useIsAdmin();

const router = useRouter();
const locale = router.locale || 'en';

return (
<Box sx={sx}>
<Box>
Expand All @@ -66,7 +77,7 @@ const ServerRow: FC<ServerRowProps & ChakraProps> = ({ server, sx }) => {
<Image
src="https://assets.open.mp/assets/images/assets/partners.png"
alt="partner server"
title="Has partnership!"
title={translateText(locale, "Servers", "Has partnership!")}
maxWidth={7}
maxHeight={7}
width={7}
Expand All @@ -78,7 +89,7 @@ const ServerRow: FC<ServerRowProps & ChakraProps> = ({ server, sx }) => {
<Image
src="https://assets.open.mp/assets/images/assets/logo-light-trans.svg"
alt="open.mp server"
title="open.mp server"
title={translateText(locale, "Servers", "open.mp server")}
maxWidth={7}
maxHeight={7}
width={7}
Expand Down Expand Up @@ -114,7 +125,7 @@ const ServerRow: FC<ServerRowProps & ChakraProps> = ({ server, sx }) => {
>
{server.pc}/{server.pm}
</Text>
<Text style={{ marginTop: "0" }}>players</Text>
<Text style={{ marginTop: "0" }}>{translateText(locale, "Servers", "players")}</Text>
</Flex>

<Box display={admin ? "block" : "none"}>
Expand Down
44 changes: 29 additions & 15 deletions frontend/src/components/site/Announcement.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,14 @@
import { Box, Heading, Text, useColorModeValue } from "@chakra-ui/react";
import React, { FC } from "react";

const translateText = require('src/components/translates/Translate');
import { useRouter } from 'next/router';

const Announcement: FC = () => {

const router = useRouter();
const locale = router.locale || 'en';

return (
<Box maxWidth="48em" mx="auto" px="0.5em">
<Box
Expand All @@ -12,21 +19,28 @@ const Announcement: FC = () => {
borderRadius="0.5em"
backgroundColor={useColorModeValue("blue.50", "gray.800")}
>
<Heading m="0" fontSize="1.5em">
open.mp launcher is out now and open source!
</Heading>

<Text>
open.mp released its own launcher to browse servers using a reliable
internet list and join your favorite servers!{" "}
<a href="https://github.com/openmultiplayer/launcher">
check out our github repository
</a>{" "}
<br />
<a href="https://github.com/openmultiplayer/launcher/releases/latest">
Download it from here.
</a>{" "}
</Text>


<Heading m="0" fontSize="1.5em">
{translateText(locale, "Announcements", "open.mp launcher is out now and open source!")}
</Heading>

<Text>
{translateText(locale, "Announcements", `open.mp released its own launcher to browse servers using a reliable internet list and join your favorite servers!`)}
{' '}
<a href="https://github.com/openmultiplayer/launcher">
{translateText(locale, "Announcements", "check out our github repository")}
</a>
{' '}
<br />
<a href="https://github.com/openmultiplayer/launcher/releases/latest">
{translateText(locale, "Announcements", "Download it from here.")}
</a>
{' '}
</Text>



</Box>
</Box>
);
Expand Down
24 changes: 17 additions & 7 deletions frontend/src/components/site/Footer.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import { Box, useColorModeValue } from "@chakra-ui/react";
import { useEffect, useState } from "react";

const translateText = require('src/components/translates/Translate');
import { useRouter } from 'next/router';


interface FooterItem {
url?: string;
imageUrl?: string;
Expand Down Expand Up @@ -81,6 +85,9 @@ const Footer: React.FC = () => {
setFormattedItems(updatedItems);
}, []);

const router = useRouter();
const locale = router.locale || 'en';

return (
<Box as="footer" bgColor={useColorModeValue("blackAlpha.800", "gray.900")} display="flex" justifyContent="space-between" padding="30px">
<div className="near-white" style={{ display: "flex", flexDirection: isMobile ? "column" : "row", justifyContent: isMobile ? "center" : "space-between", alignItems: isMobile ? "center" : "center", flex: 1 }}>
Expand All @@ -97,8 +104,10 @@ const Footer: React.FC = () => {
}}
/>
<FooterList
heading="About us"
items={[{ text: "A multiplayer mod for Grand Theft Auto: San Andreas that is <b>fully backwards compatible</b> with <b>San Andreas Multiplayer</b>." }]}
heading={translateText(locale, "Footer", "About us")}
items={[
{ text: translateText(locale, "Footer", "A multiplayer mod for Grand Theft Auto: San Andreas that is <b>fully backwards compatible</b> with <b>San Andreas Multiplayer</b>.") }
]}
alignment="center"
maxWidth={'390px'} // Max width conditionally applied
style={{
Expand All @@ -112,9 +121,10 @@ const Footer: React.FC = () => {
{!isMobile && (
<div style={{ display: 'flex', alignItems: 'center' }}>
<FooterList
heading="About us"
items={[{ text: "A multiplayer mod for Grand Theft Auto: San Andreas that is <b>fully backwards compatible</b> with <b>San Andreas Multiplayer</b>." }]}
alignment="center"
heading={translateText(locale, "Footer", "About us")}
items={[
{ text: translateText(locale, "Footer", "A multiplayer mod for Grand Theft Auto: San Andreas that is <b>fully backwards compatible</b> with <b>San Andreas Multiplayer</b>.") }
]} alignment="center"
maxWidth={'390px'} // Max width conditionally applied
style={{
whiteSpace: 'normal',
Expand Down Expand Up @@ -142,12 +152,12 @@ const Footer: React.FC = () => {
)}
<div className="near-white" style={{ textAlign: "right", flex: 1 }}>
<FooterList
heading="Community"
heading={translateText(locale, "Footer", "Community")}
items={formattedItems}
alignment="right"
/>
<FooterList
heading="More"
heading={translateText(locale, "Footer", "More")}
items={[
{ url: "/blog", imageUrl: "/images/assets/blog.svg", text: "Blog" },
{ url: "https://github.com/openmultiplayer/", imageUrl: "/images/assets/github.svg", text: "GitHub" },
Expand Down
4 changes: 3 additions & 1 deletion frontend/src/components/site/LanguageSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ interface Props {
title: string;
}

const translateText = require('src/components/translates/Translate');

const LanguageSelect = forwardRef(({ title }: Props, ref) => {
const { locale, locales, pathname, asPath, query, push } = useRouter();
const { isOpen, onOpen, onClose } = useDisclosure();
Expand Down Expand Up @@ -81,7 +83,7 @@ const LanguageSelect = forwardRef(({ title }: Props, ref) => {
<Modal isOpen={isOpen} onClose={onClose} size={modalSize}>
<ModalOverlay />
<ModalContent>
<ModalHeader>Change language from {getLanguageName(locale)}</ModalHeader>
<ModalHeader>{translateText(locale, "General", `Change language from ${getLanguageName(locale)}`)}</ModalHeader>
<ModalCloseButton />
<ModalBody>
{/* Conditionally apply flexbox layout for mobile screens */}
Expand Down
26 changes: 17 additions & 9 deletions frontend/src/components/site/NavMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import { useRouter } from "next/router";
import NextLink from "next/link";
import LanguageSelect from "./LanguageSelect";

const translateText = require('src/components/translates/Translate');

export type NavItem = {
name: string;
path: string;
Expand Down Expand Up @@ -124,14 +126,20 @@ const NavMenu: FC<Props> = ({ items, route }) => {

type NavLinkProps = { item: NavItem; current: boolean };

const NavLink: FC<NavLinkProps> = ({ item, current }) => (
<NextLink href={item.path} passHref>
<Link _hover={undefined} _focus={{ outline: 'none', border: 'none' }}>
<Button as="div" variant={current ? "outline" : "ghost"} size="sm">
{item.name}
</Button>
</Link>
</NextLink>
);
const NavLink: FC<NavLinkProps> = ({ item, current }) => {
const router = useRouter();
const locale = router.locale || 'en'; // Define locale using useRouter

return (
<NextLink href={item.path} passHref>
<Link _hover={undefined} _focus={{ outline: 'none', border: 'none' }}>
<Button as="div" variant={current ? 'outline' : 'ghost'} size="sm">
{/* Use translateText function to translate text */}
{translateText(locale, 'NavBar', item.name)}
</Button>
</Link>
</NextLink>
);
};

export default NavMenu;
28 changes: 28 additions & 0 deletions frontend/src/components/translates/Translate.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const translateText = (locale, group, key, placeholders) => {
if (locale === 'en' && !placeholders) {
return key;
}

const plainText = key.replace(/<[^>]+>/g, '');

let translation = {};
try {
translation = require(`./translations/${locale}.json`);
} catch (error) {
return translateText('en', group, key, placeholders);
}

const translatedText = translation[group]?.[plainText] || plainText;

// Replace placeholders with corresponding params if placeholders are provided
let replacedText = translatedText;
if (placeholders && typeof placeholders === 'object') {
Object.entries(placeholders).forEach(([placeholder, value]) => {
replacedText = replacedText.replace(new RegExp(`{${placeholder}}`, 'g'), value);
});
}

return replacedText;
};

module.exports = translateText;
Loading