diff --git a/components/CustomHead.tsx b/components/CustomHead.tsx
index 31b9ba1..0a217f9 100644
--- a/components/CustomHead.tsx
+++ b/components/CustomHead.tsx
@@ -1,21 +1,53 @@
/** biome-ignore-all lint/security/noDangerouslySetInnerHtml: Used as expected */
import Head from 'next/head';
import { useRouter } from 'next/router';
+import { type Messages, useTranslations } from 'next-intl';
import type { ReactElement } from 'react';
+import { NON_LOCALIZED_STRING } from '@/constants/localization';
import METADATA, { type IMetadata } from '@/constants/metadata';
import { isLocal } from '@/utils/links';
+export type MetadataLocaleKey = keyof Messages['metadata'];
interface Props {
title?: string;
+ localeKey?: MetadataLocaleKey;
metadata?: IMetadata;
structuredData?: Array;
}
export default function CustomHead(props: Props): ReactElement {
const router = useRouter();
- const { title, metadata, structuredData } = props;
- const pageTitle =
- title && title.length > 0 ? `${title} - Session Private Messenger` : METADATA.TITLE;
+ const t = useTranslations('metadata');
+ const tFeature = useTranslations('feature');
+
+ const { localeKey, metadata, structuredData } = props;
+
+ // TODO: we can probably use the locale defaults as the initialized vars
+ let title = '';
+ let description = '';
+
+ const localeArgs = {
+ appName: NON_LOCALIZED_STRING.appName,
+ appNamePossessive: NON_LOCALIZED_STRING.appNamePossessive,
+ featureCommunity: tFeature('community'),
+ };
+
+ if (localeKey) {
+ const titleKey = `${localeKey}.title` as const;
+ const pageTitle = t.has(titleKey) ? t(titleKey, localeArgs) : undefined;
+
+ title =
+ pageTitle && localeKey !== 'default'
+ ? t('default.titleLayout', { ...localeArgs, title: pageTitle })
+ : t('default.title', localeArgs);
+
+ const descriptionKey = `${localeKey}.description` as const;
+ description = t(t.has(descriptionKey) ? descriptionKey : 'default.description', localeArgs);
+ } else {
+ title = props.title || t('default.title', localeArgs);
+ description = metadata?.DESCRIPTION || t('default.description', localeArgs);
+ }
+
const pageUrl = `${METADATA.HOST_URL}${router.asPath}`;
const imageALT = metadata?.OG_IMAGE?.ALT ?? METADATA.OG_IMAGE.ALT;
let imageWidth = metadata?.OG_IMAGE?.WIDTH ?? METADATA.OG_IMAGE.WIDTH;
@@ -37,6 +69,7 @@ export default function CustomHead(props: Props): ReactElement {
}
const tags = metadata?.TAGS ? metadata?.TAGS : METADATA.TAGS;
+
const renderTags = (() => {
const keywords = ;
if (metadata?.TYPE !== 'article') return keywords;
@@ -63,6 +96,7 @@ export default function CustomHead(props: Props): ReactElement {
>
);
})();
+
const renderLdJSON = (() => {
const ldjson = `{
"@context": "https://schema.org",
@@ -72,27 +106,27 @@ export default function CustomHead(props: Props): ReactElement {
"@id": "${METADATA.HOST_URL}/#website",
"url": "${pageUrl}",
"name": "${METADATA.SITE_NAME}",
- "description": "${METADATA.DESCRIPTION}"
+ "description": "${t('default.description', localeArgs)}"
},
{
"@type": "ImageObject",
"@id": "${pageUrl}#primaryimage",
"url": "${imageUrl}",
"width": "${imageWidth}",
- "height": "${imageHeight}",
+ "height": "${imageHeight}"
},
{
"@type": "WebPage",
"@id": "${pageUrl}#webpage",
"url": "${pageUrl}",
"inLanguage": "${METADATA.LOCALE}",
- "name": "${pageTitle}",
+ "name": "${title}",
"isPartOf": { "@id": "${METADATA.HOST_URL}/#website" },
"primaryImageOfPage": {
"@id": "${pageUrl}#primaryimage"
},
"datePublished": "${metadata?.PUBLISHED_TIME ?? ''}",
- "description": "${METADATA.DESCRIPTION}"
+ "description": "${description}"
}
]
}`;
@@ -104,20 +138,47 @@ export default function CustomHead(props: Props): ReactElement {
/>
);
})();
+
+ // Generate localized page variants if localeKey is defined
+ const renderLocalizedVariants = (() => {
+ if (!localeKey || !router.locales) return null;
+
+ const currentPathWithoutLocale = router.asPath.replace(`/${router.locale}`, '') || '/';
+
+ return router.locales.map((locale) => {
+ const localizedPath =
+ locale === router.defaultLocale
+ ? currentPathWithoutLocale
+ : `/${locale}${currentPathWithoutLocale}`;
+
+ const href = `${METADATA.HOST_URL}${localizedPath}`;
+
+ return ;
+ });
+ })();
+
+ // Add x-default hreflang for the default locale
+ const renderDefaultHreflang = (() => {
+ if (!localeKey || !router.defaultLocale) return null;
+
+ const currentPathWithoutLocale = router.asPath.replace(`/${router.locale}`, '') || '/';
+ const defaultHref = `${METADATA.HOST_URL}${currentPathWithoutLocale}`;
+
+ return (
+
+ );
+ })();
+
return (
- {pageTitle}
+ {title}
-
+
-
+
-
+
@@ -144,12 +201,8 @@ export default function CustomHead(props: Props): ReactElement {
-
-
+
+
@@ -159,6 +212,8 @@ export default function CustomHead(props: Props): ReactElement {
name="msapplication-TileColor"
content={METADATA.MSAPPLICATION_TILECOLOR}
/>
+ {renderLocalizedVariants}
+ {renderDefaultHreflang}
{renderTags}
@@ -218,6 +273,15 @@ export default function CustomHead(props: Props): ReactElement {
}}
/>
))}
+ {process.env.NEXT_PUBLIC_TRANSLATION_MODE === 'true' ? (
+ <>
+
+
+ >
+ ) : null}
);
}
diff --git a/components/RedirectPage.tsx b/components/RedirectPage.tsx
index 4b1bb41..aa4f88c 100644
--- a/components/RedirectPage.tsx
+++ b/components/RedirectPage.tsx
@@ -1,37 +1,60 @@
import classNames from 'classnames';
import { useRouter } from 'next/router';
+import { useTranslations } from 'next-intl';
+import { useEffect } from 'react';
import Container from '@/components/Container';
+import type { MetadataLocaleKey } from '@/components/CustomHead';
+import Layout from '@/components/ui/Layout';
+import type { IMetadata } from '@/constants/metadata';
-export default function RedirectPage() {
+type RedirectPageProps = {
+ redirectUrl: string;
+ localeKey?: MetadataLocaleKey;
+ metadata?: IMetadata;
+};
+
+export default function RedirectPage({ redirectUrl, localeKey, metadata }: RedirectPageProps) {
const router = useRouter();
+ const t = useTranslations('redirect');
+
+ useEffect(() => {
+ router.push(redirectUrl);
+ }, [router, redirectUrl]);
+
return (
-
-
- Redirecting...
-
- Click{' '}
- router.back()}
- >
- here
- {' '}
- to return to the previous page.
-
-
-
+
+
+
+
+ {t('heading')}
+
+
+ {t.rich('content', {
+ button: (chunk) => (
+ router.back()}
+ >
+ {chunk}
+
+ ),
+ })}
+
+
+
+
);
}
diff --git a/components/cards/BenefitsCard.tsx b/components/cards/BenefitsCard.tsx
index 39b97eb..ad09077 100644
--- a/components/cards/BenefitsCard.tsx
+++ b/components/cards/BenefitsCard.tsx
@@ -1,12 +1,14 @@
import classNames from 'classnames';
import Image from 'next/legacy/image';
-import type { ReactElement } from 'react';
+import { useTranslations } from 'next-intl';
+import type { ReactNode } from 'react';
+import { NON_LOCALIZED_STRING } from '@/constants/localization';
import { useScreen } from '@/contexts/screen';
+import capitalize from '@/utils/capitalize';
import redact from '@/utils/redact';
interface Props {
- title: string;
- description?: string[];
+ itemNumber: '1' | '2' | '3' | '4' | '5' | '6';
images: string[]; // toggle images on hover [original, redacted]
imageAlt: string;
imageWidth: number;
@@ -14,9 +16,26 @@ interface Props {
classes?: string;
}
-export default function BenefitsCard(props: Props): ReactElement {
+export default function BenefitsCard(props: Props): ReactNode {
+ const t = useTranslations('landing.benefits');
+ const tFeature = useTranslations('feature');
const { isSmall } = useScreen();
- const { title, description, images, imageAlt, imageWidth, imageHeight, classes } = props;
+
+ const { images, itemNumber, imageAlt, imageWidth, imageHeight, classes } = props;
+
+ if (!t.has(`${itemNumber}.heading` as const) || !t.has(`${itemNumber}.content` as const)) {
+ return null;
+ }
+
+ const title = t(`${itemNumber}.heading` as const);
+ const rawDescription = t.rich(`${itemNumber}.content` as const, {
+ br: () => null,
+ appName: NON_LOCALIZED_STRING.appName,
+ appNamePossessive: NON_LOCALIZED_STRING.appNamePossessive,
+ featureAccountIds: tFeature('accountIds'),
+ featureNodes: tFeature('nodes'),
+ });
+
const redactedClasses = redact({
redactColor: 'gray-dark',
textColor: 'gray-dark',
@@ -27,6 +46,7 @@ export default function BenefitsCard(props: Props): ReactElement {
{
- return description?.map((line) => {
+ const nodes = Array.isArray(rawDescription) ? rawDescription : [rawDescription];
+ return nodes.map((line) => {
return (
{line}
@@ -71,7 +93,7 @@ export default function BenefitsCard(props: Props): ReactElement {
return (
{renderImages}
- {title}
+ {title}
{renderDescription}
);
diff --git a/components/cards/PostCard.tsx b/components/cards/PostCard.tsx
index 3502595..2afed5d 100644
--- a/components/cards/PostCard.tsx
+++ b/components/cards/PostCard.tsx
@@ -1,6 +1,7 @@
import classNames from 'classnames';
import Image from 'next/legacy/image';
import Link from 'next/link';
+import { useTranslations } from 'next-intl';
import type { ReactElement } from 'react';
import type { IPost } from '@/types/cms';
@@ -13,6 +14,7 @@ interface Props extends IPost {
}
export default function PostCard(props: Props): ReactElement {
+ const t = useTranslations('blog');
const {
title,
description,
@@ -84,7 +86,7 @@ export default function PostCard(props: Props): ReactElement {
)}
{featured && (
- Read More »
+ {t('readMore')} »
)}
diff --git a/components/navigation/Footer.tsx b/components/navigation/Footer.tsx
index 520246c..960b89a 100644
--- a/components/navigation/Footer.tsx
+++ b/components/navigation/Footer.tsx
@@ -1,6 +1,7 @@
import classNames from 'classnames';
import Image from 'next/legacy/image';
import Link from 'next/link';
+import { useTranslations } from 'next-intl';
import type { FunctionComponent, ReactElement, SVGProps } from 'react';
import { ReactComponent as GithubSVG } from '@/assets/svgs/github.svg';
import { ReactComponent as InstagramSVG } from '@/assets/svgs/instagram.svg';
@@ -8,12 +9,12 @@ import { ReactComponent as MastodonSVG } from '@/assets/svgs/mastodon.svg';
import { ReactComponent as RssSVG } from '@/assets/svgs/rss.svg';
import { ReactComponent as TwitterSVG } from '@/assets/svgs/twitter.svg';
import { ReactComponent as YouTubeSVG } from '@/assets/svgs/youtube.svg';
+import { NON_LOCALIZED_STRING } from '@/constants/localization';
import redact from '@/utils/redact';
// Type definitions
interface SocialLink {
href: string;
- label: string;
icon: FunctionComponent>;
external: boolean;
platform: string;
@@ -34,14 +35,12 @@ const svgClasses = classNames('fill-current w-7 h-7 m-1', 'lg:my-0 lg:ml-0', 'ho
const socialLinks: SocialLink[] = [
{
href: 'https://twitter.com/session_app',
- label: 'Follow Session on Twitter',
icon: TwitterSVG,
external: true,
platform: 'Twitter',
},
{
href: 'https://mastodon.social/@session',
- label: 'Follow Session on Mastodon',
icon: MastodonSVG,
external: true,
platform: 'Mastodon',
@@ -50,28 +49,24 @@ const socialLinks: SocialLink[] = [
},
{
href: 'https://www.instagram.com/getsession',
- label: 'Follow Session on Instagram',
icon: InstagramSVG,
external: true,
platform: 'Instagram',
},
{
href: 'https://www.youtube.com/@SessionTV',
- label: 'Subscribe to Session on YouTube',
icon: YouTubeSVG,
external: true,
platform: 'YouTube',
},
{
href: 'https://github.com/session-foundation',
- label: 'View Session on GitHub',
icon: GithubSVG,
external: true,
platform: 'GitHub',
},
{
href: '/feed',
- label: 'Subscribe to Session RSS feed',
icon: RssSVG,
external: false,
platform: 'RSS',
@@ -79,38 +74,45 @@ const socialLinks: SocialLink[] = [
];
function SocialLinks() {
+ const t = useTranslations('footer.aria');
return (
-
- {socialLinks.map((social: SocialLink) => {
- const IconComponent = social.icon;
+
+ {socialLinks.map(
+ ({ platform, href, external, customIconClasses, icon: IconComponent }: SocialLink) => {
+ const label =
+ platform === 'RSS'
+ ? t('rssLink')
+ : t('socialLink', { appName: NON_LOCALIZED_STRING.appName, platform });
- return (
-
-
-
- {social.label}
-
-
- );
- })}
+ return (
+
+
+
+ {label}
+
+
+ );
+ }
+ )}
);
}
export default function Footer(): ReactElement {
+ const t = useTranslations('footer');
+ const tNav = useTranslations('navigation');
+ const tGeneral = useTranslations('general');
+ const tAbout = useTranslations('landing.about');
const redactedClasses = redact({
redactColor: 'primary',
textColor: 'white',
@@ -134,37 +136,37 @@ export default function Footer(): ReactElement {
)}
>
-
About
+ {t('about')}
- Whitepaper
+ {tGeneral('whitepaper')}
- Privacy Policy
+ {tGeneral('privacyPolicy')}
- Terms of Service
+ {tGeneral('termsOfService')}
- Blog
+ {tNav('blog')}
- FAQ
+ {tNav('faq')}
-
Other
+ {tGeneral('other')}
- Session Token
+ {NON_LOCALIZED_STRING.appToken}
- Lokinet
+ {NON_LOCALIZED_STRING.lokinet}
- Media Kit
+ {t('mediaKit')}
- Transparency Report
+ {t('transparencyReport')}
- Foundation
+ {t('foundation')}
-
Socials
+ {t('socials')}
@@ -223,6 +227,7 @@ export default function Footer(): ReactElement {
- Session is an end-to-end encrypted messenger
- that protects your personal data. Take back
- control with a messaging app designed, built, and operated by a{' '}
- global community of{' '}
- privacy experts.
+ {tAbout.rich('content', {
+ span: (chunk) => {chunk} ,
+ appName: NON_LOCALIZED_STRING.appName,
+ })}
diff --git a/components/navigation/Locale.tsx b/components/navigation/Locale.tsx
new file mode 100644
index 0000000..f1f7173
--- /dev/null
+++ b/components/navigation/Locale.tsx
@@ -0,0 +1,70 @@
+import classNames from 'classnames';
+import Link from 'next/link';
+import { useRouter } from 'next/router';
+import { useLocale, useTranslations } from 'next-intl';
+import {
+ DialogContent,
+ DialogDescription,
+ DialogHeader,
+ DialogTitle,
+} from '@/components/ui/Dialog';
+
+function getLanguageDisplayName(locale: string) {
+ try {
+ return new Intl.DisplayNames([locale], { type: 'language' }).of(locale);
+ } catch {
+ return locale.toUpperCase();
+ }
+}
+
+export function LocaleDialogContent() {
+ const router = useRouter();
+ const currentLocale = useLocale();
+ const t = useTranslations('languageSelection');
+
+ return (
+
+
+ {t('title')}
+
+
+ {t('description')}
+
+
+ {router.locales?.map((locale) => {
+ const isCurrentLocale = locale === currentLocale;
+ const languageName = getLanguageDisplayName(locale) ?? locale;
+
+ return (
+
+
+
+
+ {languageName}{' '}
+ ({locale})
+
+ {isCurrentLocale && (
+ {t('aria.currentLanguageIndicator')}
+ )}
+
+
+
+ );
+ })}
+
+
+ );
+}
diff --git a/components/navigation/Nav.tsx b/components/navigation/Nav.tsx
index faf7aea..c49eb7a 100644
--- a/components/navigation/Nav.tsx
+++ b/components/navigation/Nav.tsx
@@ -1,14 +1,24 @@
import classNames from 'classnames';
+import { GlobeIcon } from 'lucide-react';
import Image from 'next/legacy/image';
import Link from 'next/link';
+import { useRouter } from 'next/router';
+import { useTranslations } from 'next-intl';
import { type ReactElement, useState } from 'react';
import { ReactComponent as CloseSVG } from '@/assets/svgs/close.svg';
import { ReactComponent as MenuSVG } from '@/assets/svgs/hamburger.svg';
-import NavItem from '@/components/navigation/NavItem';
+import { LocaleDialogContent } from '@/components/navigation/Locale';
+import NavItem, { navLinkClasses, navLinkHoverClasses } from '@/components/navigation/NavItem';
import Button from '@/components/ui/Button';
+import { Dialog, DialogTrigger } from '@/components/ui/Dialog';
import { NAVIGATION } from '@/constants';
+import { NON_LOCALIZED_STRING } from '@/constants/localization';
+import type { NavItemKey } from '@/constants/navigation';
export default function Nav(): ReactElement {
+ const t = useTranslations('navigation');
+ const tGeneral = useTranslations('general');
+ const router = useRouter();
const [isExpanded, setIsExpanded] = useState(false);
const toggleNav = () => {
setIsExpanded(!isExpanded);
@@ -31,6 +41,7 @@ export default function Nav(): ReactElement {
- {isExpanded ? 'Close' : 'Open'} navigation menu
+
+ {t(isExpanded ? 'aria.iconButtonClose' : 'aria.iconButtonOpen')}
+
{Object.entries(NAVIGATION.NAV_ITEMS).map(([key, value], index) => {
+ const titleKey = key as NavItemKey;
+ const title = t.has(titleKey) ? t(titleKey) : key;
return (
);
})}
+
+
+
+ {router.locale}
+
+
+
-
- Download
+
+ {tGeneral('download')}
diff --git a/components/navigation/NavItem.tsx b/components/navigation/NavItem.tsx
index 1f94e16..287b765 100644
--- a/components/navigation/NavItem.tsx
+++ b/components/navigation/NavItem.tsx
@@ -5,10 +5,12 @@
import classNames from 'classnames';
import Link from 'next/link';
import { useRouter } from 'next/router';
+import { useTranslations } from 'next-intl';
import { type ReactElement, type ReactNode, useEffect, useState } from 'react';
import { ReactComponent as CloseSVG } from '@/assets/svgs/close.svg';
import { ReactComponent as MenuSVG } from '@/assets/svgs/hamburger.svg';
-import type { INavItem } from '@/constants/navigation';
+import { NON_LOCALIZED_STRING } from '@/constants/localization';
+import type { INavItem, NavItemKey } from '@/constants/navigation';
import { useScreen } from '@/contexts/screen';
interface DropdownProps {
@@ -24,23 +26,27 @@ interface NavItemProps extends DropdownProps {
zIndex?: number;
}
+export const navItemClasses = classNames(
+ 'bg-gray-dark block w-full px-5 py-2 uppercase border-transparent border-b-3',
+ 'lg:px-2 lg:py-1 lg:mx-auto lg:bg-white lg:last:rounded-b-md'
+);
+
+export const navItemHoverClasses = classNames(
+ 'transition-colors duration-300',
+ 'hover:bg-gray-light lg:hover:text-primary lg:hover:bg-white'
+);
+
function NavDropdown(props: DropdownProps): ReactElement {
const { title, navItem } = props;
+ const t = useTranslations('navigation');
+ const ariaKey = `aria.${title}` as NavItemKey;
- const navItemClasses = classNames(
- 'bg-gray-dark block w-full px-5 py-2 uppercase border-transparent border-b-3',
- 'lg:px-2 lg:py-1 lg:mx-auto lg:bg-white lg:last:rounded-b-md'
- );
-
- const navItemHoverClasses = classNames(
- 'transition-colors duration-300',
- 'hover:bg-gray-light lg:hover:text-primary lg:hover:bg-white'
- );
+ const aria = t.has(ariaKey) ? t(ariaKey, { appName: NON_LOCALIZED_STRING.appName }) : undefined;
return (
{
setIsDropdownExpanded(false);
}, []);
@@ -79,7 +89,7 @@ export default function NavItem(props: NavItemProps): ReactElement {
{!navItem.items ? (
- More posts
+ {t('morePosts')}
)}
(null);
const { isSmall, isMedium } = useScreen();
const redactedOptions = {
@@ -46,7 +49,7 @@ export default function About(): ReactElement {
large: '67rem',
}}
>
- What is Session?
+ {t('title', { appName: NON_LOCALIZED_STRING.appName })}
- Session is an end-to-end encrypted messenger that
- protects your personal data. Take back control
- with a messaging app designed, built, and operated by a{' '}
- global community of{' '}
- privacy experts.
+ {t.rich('content', {
+ span: (chunk) => {chunk} ,
+ appName: NON_LOCALIZED_STRING.appName,
+ })}
diff --git a/components/sections/Benefits.tsx b/components/sections/Benefits.tsx
index 6e8b998..64fb305 100644
--- a/components/sections/Benefits.tsx
+++ b/components/sections/Benefits.tsx
@@ -1,10 +1,12 @@
import classNames from 'classnames';
+import { useTranslations } from 'next-intl';
import type { ReactElement } from 'react';
import Container from '@/components/Container';
import BenefitsCard from '@/components/cards/BenefitsCard';
import Headline from '@/components/ui/Headline';
export default function Benefits(): ReactElement {
+ const t = useTranslations('landing.benefits');
const cardClasses = classNames('w-full mb-5');
const imageWidth = 500;
const imageHeight = 500;
@@ -19,7 +21,7 @@ export default function Benefits(): ReactElement {
large: '67rem',
}}
>
- Benefits
+ {t('title')}
diff --git a/components/sections/EmailSignup.tsx b/components/sections/EmailSignup.tsx
index b275dc3..1a41b46 100644
--- a/components/sections/EmailSignup.tsx
+++ b/components/sections/EmailSignup.tsx
@@ -1,4 +1,5 @@
import classNames from 'classnames';
+import { useTranslations } from 'next-intl';
import { type FormEventHandler, type ReactElement, useRef, useState } from 'react';
import Container from '@/components/Container';
import GroupNotice from '@/components/sections/GroupNotice';
@@ -6,6 +7,7 @@ import Button from '@/components/ui/Button';
import { useScreen } from '@/contexts/screen';
export default function EmailSignup(): ReactElement {
+ const t = useTranslations('email');
const { isSmall } = useScreen();
const [submitted, setSubmitted] = useState(false);
@@ -46,18 +48,16 @@ export default function EmailSignup(): ReactElement {
};
return (
- {isSmall && }
+ {isSmall ? : null}
- Every project update, delivered straight to your inbox.
+ {t('heading')}
-
- Expect an email about once a month.
-
+ {t('subheading')}
{submitted && (
- Thanks! Check your inbox to confirm your subscription.
+ {t('submitSuccessConfirm')}
)}
diff --git a/components/sections/Features.tsx b/components/sections/Features.tsx
index 479f47b..6e631bc 100644
--- a/components/sections/Features.tsx
+++ b/components/sections/Features.tsx
@@ -1,15 +1,42 @@
import classNames from 'classnames';
import Image from 'next/legacy/image';
+import { useTranslations } from 'next-intl';
import type { ReactElement } from 'react';
import Container from '@/components/Container';
import Headline from '@/components/ui/Headline';
+import capitalize from '@/utils/capitalize';
-export default function Features(): ReactElement {
- const headingClasses = classNames(
- 'font-helvetica text-3xl font-bold text-gray-dark mb-1',
- 'md:text-4xl'
+const headingClasses = classNames(
+ 'font-helvetica text-3xl font-bold text-gray-dark mb-1',
+ 'md:text-4xl'
+);
+
+const paragraphClasses = classNames('text-gray-lighter leading-6 mb-8', 'md:mb-12');
+
+type FeatureSectionProps = {
+ itemNumber: '1' | '2' | '3';
+};
+
+function FeatureSection({ itemNumber }: FeatureSectionProps) {
+ const t = useTranslations('landing.features');
+ const tFeature = useTranslations('feature');
+ return (
+ <>
+ {t(`${itemNumber}.heading` as const)}
+
+ {t(`${itemNumber}.content` as const, {
+ featureGroup: tFeature('group'),
+ featureCommunity: tFeature('community'),
+ })}
+
+ >
);
- const paragraphClasses = classNames('text-gray-lighter leading-6 mb-8', 'md:mb-12');
+}
+
+export default function Features(): ReactElement {
+ const t = useTranslations('landing.features');
+ const tImage = useTranslations('imageAlt');
+
return (
- Features
+ {t('title')}
- Enjoy the features you love and the security you need.
+ {t('heading')}
- Speak freely
-
- Only you and the person you are speaking to can ever see your messages. Enjoy the
- feeling of freedom with end-to-end encryption and disappearing messages.
-
- Stay in control
-
- You are in control of your messages from start to finish. Whether it’s managing
- your own encryption keys or choosing a custom theme—Session puts you in charge.
-
- Keep up with your crowd
-
- Whether you’re catching up with close friends or organizing a major event,
- it’s effortless with secure Group and Community (100+ members) chats.
-
+
+
+
- Join the{' '}
-
- Session Community
- {' '}
- and meet the vibrant group of people building, running, and using Session.
+ {t.rich('joinCommunity', {
+ appName: NON_LOCALIZED_STRING.appName,
+ featureCommunity: tFeature('community'),
+ button: (chunk) => (
+
+ {chunk}
+
+ ),
+ })}
);
diff --git a/components/sections/Hero.tsx b/components/sections/Hero.tsx
index 5873bdd..2de8074 100644
--- a/components/sections/Hero.tsx
+++ b/components/sections/Hero.tsx
@@ -1,6 +1,7 @@
import classNames from 'classnames';
import Image from 'next/legacy/image';
import Link from 'next/link';
+import { useTranslations } from 'next-intl';
import type { ReactElement } from 'react';
import { ReactComponent as AndroidSVG } from '@/assets/svgs/android_robot_head.svg';
import { ReactComponent as AppleSVG } from '@/assets/svgs/apple.svg';
@@ -8,10 +9,15 @@ import { ReactComponent as DesktopSVG } from '@/assets/svgs/desktop.svg';
import { ReactComponent as FDroidSVG } from '@/assets/svgs/fdroid-logo.svg';
import Container from '@/components/Container';
import Button from '@/components/ui/Button';
+import { NON_LOCALIZED_STRING } from '@/constants/localization';
+import capitalize from '@/utils/capitalize';
export default function Hero(): ReactElement {
+ const t = useTranslations('landing.hero');
+ const tGeneral = useTranslations('general');
+ const tImage = useTranslations('imageAlt');
const headingClasses = classNames(
- 'text-4xl font-semibold text-gray-dark mb-4',
+ 'text-4xl font-semibold text-gray-dark mb-4 whitespace-nowrap',
'md:text-5xl',
'lg:text-6xl'
);
@@ -22,12 +28,21 @@ export default function Hero(): ReactElement {
);
const downloadLinkClasses = 'text-3xl font-bold text-primary mb-7';
const downloadSVGClasses = 'inline-block mx-3 -mt-2 fill-current';
+
+ const heroText = t.rich('heading', {
+ glitch: (chunk) => (
+
+ {chunk}
+
+ ),
+ });
+
return (
-
+
-
- Send
-
- Messages,
-
- Not Metadata.
-
-
Find your freedom with Session
+
{heroText}
+
+ {t('tag', { appName: NON_LOCALIZED_STRING.appName })}
+
- Download
+ {tGeneral('download')}
diff --git a/components/ui/Accordion.tsx b/components/ui/Accordion.tsx
index e4607a7..940f831 100644
--- a/components/ui/Accordion.tsx
+++ b/components/ui/Accordion.tsx
@@ -1,10 +1,11 @@
/** biome-ignore-all lint/a11y/useKeyWithClickEvents: TODO: refactor this to be more accessible */
+/** biome-ignore-all lint/correctness/useExhaustiveDependencies: TODO: makes it work, but its not good, we want to remove the need to use js for this */
/** biome-ignore-all lint/a11y/noStaticElementInteractions: TODO: refactor this to be more accessible */
import type { Document } from '@contentful/rich-text-types';
import classNames from 'classnames';
import Link from 'next/link';
-import { type ReactElement, useCallback, useEffect, useRef, useState } from 'react';
+import { type ReactElement, useEffect, useRef, useState } from 'react';
import { ReactComponent as LinkSVG } from '@/assets/svgs/link.svg';
import { ReactComponent as MinusSVG } from '@/assets/svgs/minus.svg';
import { ReactComponent as PlusSVG } from '@/assets/svgs/plus.svg';
@@ -35,10 +36,10 @@ export default function Accordion(props: Props): ReactElement {
const [height, setHeight] = useState(`${content?.current?.scrollHeight}px`);
const [loaded, setLoaded] = useState(false);
- const handleExpand = useCallback(() => {
+ const handleExpand = () => {
setIsExpanded(!isExpanded);
setHeight(isExpanded ? '0px' : `${content?.current?.scrollHeight}px`);
- }, [isExpanded]);
+ };
const svgClasses = classNames('w-3 h-3 fill-current mb-1 mr-2');
useEffect(() => {
@@ -67,13 +68,13 @@ export default function Accordion(props: Props): ReactElement {
setHeight(`${content?.current?.scrollHeight}px`);
}
setLoaded(true);
- }, [expand, handleExpand]);
+ }, [expand]);
useEffect(() => {
if (loaded && expand) {
handleExpand();
}
- }, [expand, handleExpand, loaded]);
+ }, [expand, loaded]);
return (
& {
bgColor?: 'primary' | 'black' | 'none';
textColor?: 'primary' | 'black';
size?: 'small' | 'medium' | 'large';
@@ -12,9 +12,7 @@ interface Props {
type?: 'submit';
reference?: LegacyRef
;
classes?: string;
- children?: string;
- onClick: MouseEventHandler;
-}
+};
export default function Button(props: Props): ReactElement {
const {
@@ -28,9 +26,9 @@ export default function Button(props: Props): ReactElement {
animate = false,
hoverEffect = true,
classes,
- children,
- onClick,
+ ...rest
} = props;
+
// See Gotchas in README
const bgClasses = [
bgColor === 'primary' && 'bg-primary',
@@ -64,6 +62,7 @@ export default function Button(props: Props): ReactElement {
return (
- {children}
-
+ />
);
}
diff --git a/components/ui/Dialog.tsx b/components/ui/Dialog.tsx
new file mode 100644
index 0000000..2d7686b
--- /dev/null
+++ b/components/ui/Dialog.tsx
@@ -0,0 +1,127 @@
+'use client';
+
+import * as DialogPrimitive from '@radix-ui/react-dialog';
+import classNames from 'classnames';
+import { XIcon } from 'lucide-react';
+import type { ComponentProps } from 'react';
+
+const cn = classNames;
+
+function Dialog({ ...props }: ComponentProps) {
+ return ;
+}
+
+function DialogTrigger({ ...props }: ComponentProps) {
+ return ;
+}
+
+function DialogPortal({ ...props }: ComponentProps) {
+ return ;
+}
+
+function DialogClose({ ...props }: ComponentProps) {
+ return ;
+}
+
+function DialogOverlay({ className, ...props }: ComponentProps) {
+ return (
+
+ );
+}
+
+function DialogContent({
+ className,
+ children,
+ showCloseButton = true,
+ ...props
+}: ComponentProps & {
+ showCloseButton?: boolean;
+}) {
+ return (
+
+
+
+ {children}
+ {showCloseButton && (
+
+
+ Close
+
+ )}
+
+
+ );
+}
+
+function DialogHeader({ className, ...props }: ComponentProps<'div'>) {
+ return (
+
+ );
+}
+
+function DialogFooter({ className, ...props }: ComponentProps<'div'>) {
+ return (
+
+ );
+}
+
+function DialogTitle({ className, ...props }: ComponentProps) {
+ return (
+
+ );
+}
+
+function DialogDescription({
+ className,
+ ...props
+}: ComponentProps) {
+ return (
+
+ );
+}
+
+export {
+ Dialog,
+ DialogClose,
+ DialogContent,
+ DialogDescription,
+ DialogFooter,
+ DialogHeader,
+ DialogOverlay,
+ DialogPortal,
+ DialogTitle,
+ DialogTrigger,
+};
diff --git a/components/ui/Layout.tsx b/components/ui/Layout.tsx
index 9c70d1c..0206e1d 100644
--- a/components/ui/Layout.tsx
+++ b/components/ui/Layout.tsx
@@ -1,4 +1,5 @@
import { useRouter } from 'next/router';
+import type { Messages } from 'next-intl';
import { type ReactElement, type ReactNode, useMemo } from 'react';
import CustomHead from '@/components/CustomHead';
import LockedPage from '@/components/LockedPage';
@@ -9,6 +10,7 @@ import Banner from '@/components/ui/Banner';
import type { IMetadata } from '@/constants/metadata';
interface Props {
+ localeKey?: keyof Messages['metadata'];
title?: string;
metadata?: IMetadata;
children: ReactNode;
@@ -17,6 +19,7 @@ interface Props {
}
export default function Layout({
+ localeKey,
title,
metadata,
children,
@@ -35,10 +38,15 @@ export default function Layout({
return (
<>
-
+
{showBanner ? : null}
- {locked ? : {children} }
+ {locked ? : {children} }
>
diff --git a/constants/localization.ts b/constants/localization.ts
new file mode 100644
index 0000000..0a6376f
--- /dev/null
+++ b/constants/localization.ts
@@ -0,0 +1,6 @@
+export enum NON_LOCALIZED_STRING {
+ appName = 'Session',
+ appNamePossessive = "Session's",
+ appToken = 'Session Token',
+ lokinet = 'Lokinet',
+}
diff --git a/constants/metadata.ts b/constants/metadata.ts
index cdcaf7b..daab447 100644
--- a/constants/metadata.ts
+++ b/constants/metadata.ts
@@ -1,5 +1,5 @@
export interface IMetadata {
- DESCRIPTION: string;
+ DESCRIPTION?: string;
TYPE?: string;
CANONICAL_URL?: string;
OG_IMAGE?: {
@@ -19,9 +19,6 @@ const METADATA = {
? 'https://getsession.org'
: 'https://staging.getsession.org',
SITE_NAME: 'Session',
- TITLE: 'Session | Send Messages, Not Metadata. | Private Messenger',
- DESCRIPTION:
- 'Session is a private messenger that aims to remove any chance of metadata collection by routing all messages through an onion routing network.',
TAGS: [
'Privacy',
'co-op',
@@ -90,8 +87,31 @@ const METADATA = {
DESCRIPTION: 'How you can help. A Session Community Help Guide Document.',
},
LITEPAPER_PAGE: {
- DESCRIPTION:
- 'Session is a decentralised messenger that supports completely private, secure, and anonymous communications.',
+ OG_IMAGE: {
+ URL: '/assets/images/litepaper.png',
+ WIDTH: 1200,
+ HEIGHT: 627,
+ ALT: 'Black background with a neon white Session logo with Litepaper written as a heading',
+ },
+ TAGS: [
+ 'Session',
+ 'Session Foundation',
+ 'litepaper',
+ 'lightpaper',
+ 'metadata',
+ 'messenger',
+ 'encryption',
+ 'encrypted',
+ 'onion routing',
+ 'decentralisation',
+ 'Oxen',
+ 'blockchain',
+ 'messaging',
+ 'private',
+ 'privacy',
+ ],
+ },
+ WHITEPAPER_PAGE: {
OG_IMAGE: {
URL: '/assets/images/litepaper.png',
WIDTH: 1200,
diff --git a/constants/navigation.ts b/constants/navigation.ts
index ea7fa07..8bf3cb5 100644
--- a/constants/navigation.ts
+++ b/constants/navigation.ts
@@ -1,73 +1,66 @@
+import type { Messages } from 'next-intl';
+
export interface INavItem {
href: string;
- alt: string;
target: '_self' | '_blank';
rel?: string;
items?: INavList;
}
+export type NavItemKey = keyof Omit;
-interface INavList {
- [key: string]: INavItem; // key is what user sees
-}
+type INavList = Record;
const NAV_ITEMS: INavList = {
- Blog: {
+ blog: {
href: '/blog',
- alt: `Link to Session's blogposts`,
target: '_self',
},
- Resources: {
+ resources: {
href: '/resources',
- alt: 'Heading of Session Resources Links',
target: '_self',
items: {
- GitHub: {
+ github: {
href: 'https://github.com/session-foundation',
- alt: 'Link to Session Foundation GitHub page',
target: '_blank',
rel: 'noopener noreferrer',
},
- Docs: {
+ docs: {
href: 'https://docs.getsession.org',
- alt: 'Link to Session Docs website',
target: '_blank',
rel: 'noopener noreferrer',
},
- Whitepaper: {
+ whitepaper: {
href: '/whitepaper',
- alt: 'Link to Session Whitepaper',
target: '_blank',
rel: 'noopener noreferrer',
},
- Litepaper: {
+ litepaper: {
href: '/litepaper',
- alt: 'Link to Session Litepaper',
target: '_self',
},
},
},
- Network: {
+ network: {
href: '/network',
- alt: 'Heading of Session Network Links',
target: '_self',
items: {
- 'Session Token': {
+ 'session token': {
href: 'https://token.getsession.org/',
- alt: 'Link to Session Token website',
target: '_blank',
rel: 'noopener noreferrer',
},
},
},
- Help: {
+ help: {
href: '/help',
- alt: 'Heading of Session Help Links',
target: '_self',
items: {
- FAQ: { href: '/faq', alt: `Link to Session's FAQs`, target: '_self' },
- Support: {
+ faq: {
+ href: '/faq',
+ target: '_self',
+ },
+ support: {
href: 'https://sessionapp.zendesk.com/hc/en-us',
- alt: 'Link to Session Support via Zendesk',
target: '_blank',
rel: 'noopener noreferrer',
},
diff --git a/global.d.ts b/global.d.ts
new file mode 100644
index 0000000..3f300f2
--- /dev/null
+++ b/global.d.ts
@@ -0,0 +1,10 @@
+import type en from './locales/en.json';
+
+type Messages = typeof en;
+
+declare module 'next-intl' {
+ interface AppConfig {
+ // ...
+ Messages: Messages;
+ }
+}
diff --git a/locales/ach.json b/locales/ach.json
new file mode 100644
index 0000000..805fc9b
--- /dev/null
+++ b/locales/ach.json
@@ -0,0 +1,176 @@
+{
+ "feature": {
+ "accountIds": "crwdns38006:0crwdne38006:0",
+ "nodes": "crwdns38008:0crwdne38008:0",
+ "group": "crwdns38010:0crwdne38010:0",
+ "community": "crwdns38012:0crwdne38012:0"
+ },
+ "general": {
+ "download": "crwdns38014:0crwdne38014:0",
+ "whitepaper": "crwdns38016:0crwdne38016:0",
+ "litepaper": "crwdns38018:0crwdne38018:0",
+ "messages": "crwdns38020:0crwdne38020:0",
+ "metadata": "crwdns38022:0crwdne38022:0",
+ "privacyPolicy": "crwdns38024:0crwdne38024:0",
+ "termsOfService": "crwdns38026:0crwdne38026:0",
+ "other": "crwdns38028:0crwdne38028:0"
+ },
+ "navigation": {
+ "blog": "crwdns38030:0crwdne38030:0",
+ "resources": "crwdns38032:0crwdne38032:0",
+ "docs": "crwdns38034:0crwdne38034:0",
+ "network": "crwdns38036:0crwdne38036:0",
+ "help": "crwdns38038:0crwdne38038:0",
+ "faq": "crwdns38040:0crwdne38040:0",
+ "support": "crwdns38042:0crwdne38042:0",
+ "aria": {
+ "whitepaper": "crwdns38044:0{appName}crwdne38044:0",
+ "litepaper": "crwdns38046:0{appName}crwdne38046:0",
+ "sessionToken": "crwdns38048:0{appName}crwdne38048:0",
+ "support": "crwdns38050:0{appName}crwdne38050:0",
+ "iconButtonOpen": "crwdns38052:0crwdne38052:0",
+ "iconButtonClose": "crwdns38054:0crwdne38054:0",
+ "downloadButton": "crwdns38056:0{appName}crwdne38056:0"
+ }
+ },
+ "footer": {
+ "about": "crwdns38058:0crwdne38058:0",
+ "mediaKit": "crwdns38060:0crwdne38060:0",
+ "transparencyReport": "crwdns38062:0crwdne38062:0",
+ "foundation": "crwdns38064:0crwdne38064:0",
+ "appSupport": "crwdns38066:0{appName}crwdne38066:0",
+ "socials": "crwdns38068:0crwdne38068:0",
+ "aria": {
+ "socialLink": "crwdns38070:0{appName}crwdnd38070:0{platform}crwdne38070:0",
+ "rssLink": "crwdns38072:0crwdne38072:0"
+ }
+ },
+ "languageSelection": {
+ "title": "crwdns38074:0crwdne38074:0",
+ "description": "crwdns38076:0crwdne38076:0",
+ "aria": {
+ "currentLanguage": "crwdns38078:0{language}crwdne38078:0",
+ "switchToLanguage": "crwdns38080:0{language}crwdne38080:0",
+ "currentLanguageIndicator": "crwdns38082:0crwdne38082:0"
+ }
+ },
+ "notFound": {
+ "pageNotFound": "crwdns38084:0crwdne38084:0",
+ "description": "crwdns38086:0crwdne38086:0"
+ },
+ "email": {
+ "heading": "crwdns38088:0crwdne38088:0",
+ "subheading": "crwdns38090:0crwdne38090:0",
+ "placeholder": "crwdns38092:0crwdne38092:0",
+ "submitSuccessConfirm": "crwdns38094:0crwdne38094:0",
+ "button": {
+ "text": "crwdns38096:0crwdne38096:0"
+ },
+ "joinCommunity": "crwdns38098:0{appName}crwdnd38098:0{featureCommunity}crwdne38098:0"
+ },
+ "landing": {
+ "hero": {
+ "heading": "crwdns38204:0crwdne38204:0",
+ "tag": "crwdns38102:0{appName}crwdne38102:0",
+ "glitchTextGlitch": "crwdns38106:0crwdne38106:0"
+ },
+ "about": {
+ "title": "crwdns38108:0{appName}crwdne38108:0",
+ "content": "crwdns38110:0{appName}crwdne38110:0"
+ },
+ "benefits": {
+ "title": "crwdns38112:0crwdne38112:0",
+ "1": {
+ "heading": "crwdns38114:0crwdne38114:0",
+ "content": "crwdns38116:0{featureAccountIds}crwdne38116:0"
+ },
+ "2": {
+ "heading": "crwdns38118:0crwdne38118:0",
+ "content": "crwdns38120:0{appName}crwdne38120:0"
+ },
+ "3": {
+ "heading": "crwdns38122:0crwdne38122:0",
+ "content": "crwdns38124:0crwdne38124:0"
+ },
+ "4": {
+ "heading": "crwdns38126:0crwdne38126:0",
+ "content": "crwdns38128:0{appName}crwdne38128:0"
+ },
+ "5": {
+ "heading": "crwdns38130:0crwdne38130:0",
+ "content": "crwdns38132:0{featureNodes}crwdnd38132:0{appName}crwdne38132:0"
+ },
+ "6": {
+ "heading": "crwdns38134:0crwdne38134:0",
+ "content": "crwdns38136:0crwdne38136:0"
+ }
+ },
+ "features": {
+ "title": "crwdns38138:0crwdne38138:0",
+ "heading": "crwdns38140:0crwdne38140:0",
+ "1": {
+ "heading": "crwdns38142:0crwdne38142:0",
+ "content": "crwdns38144:0crwdne38144:0"
+ },
+ "2": {
+ "heading": "crwdns38146:0crwdne38146:0",
+ "content": "crwdns38148:0crwdne38148:0"
+ },
+ "3": {
+ "heading": "crwdns38150:0crwdne38150:0",
+ "content": "crwdns38152:0{featureGroup}crwdnd38152:0{featureCommunity}crwdne38152:0"
+ }
+ }
+ },
+ "redirect": {
+ "heading": "crwdns38154:0crwdne38154:0",
+ "content": "crwdns38156:0crwdne38156:0"
+ },
+ "blog": {
+ "readMore": "crwdns38158:0crwdne38158:0",
+ "morePosts": "crwdns38160:0crwdne38160:0"
+ },
+ "download": {
+ "heading": "crwdns38162:0{appName}crwdne38162:0",
+ "mobile": "crwdns38164:0crwdne38164:0",
+ "desktop": "crwdns38166:0crwdne38166:0",
+ "verifySignatures": "crwdns38168:0{platforms}crwdne38168:0",
+ "releaseNotes": "crwdns38170:0{platforms}crwdne38170:0"
+ },
+ "imageAlt": {
+ "hero": "crwdns38172:0crwdne38172:0",
+ "appLaptop": "crwdns38174:0crwdne38174:0",
+ "appMobile": "crwdns38176:0crwdne38176:0"
+ },
+ "metadata": {
+ "default": {
+ "titleLayout": "crwdns38178:0{title}crwdnd38178:0{appName}crwdne38178:0",
+ "title": "crwdns38180:0{appName}crwdne38180:0",
+ "description": "crwdns38182:0{appName}crwdne38182:0"
+ },
+ "download": {
+ "title": "crwdns38184:0crwdne38184:0",
+ "description": "crwdns38186:0{appName}crwdnd38186:0{appName}crwdne38186:0"
+ },
+ "faq": {
+ "title": "crwdns38188:0crwdne38188:0",
+ "description": "crwdns38190:0{appName}crwdne38190:0"
+ },
+ "litepaper": {
+ "description": "crwdns38192:0{appName}crwdne38192:0",
+ "title": "crwdns38456:0{appName}crwdne38456:0"
+ },
+ "whitepaper": {
+ "description": "crwdns38194:0{appName}crwdne38194:0",
+ "title": "crwdns38458:0{appName}crwdne38458:0"
+ },
+ "community": {
+ "title": "crwdns38196:0{appName}crwdnd38196:0{featureCommunity}crwdne38196:0",
+ "description": "crwdns38198:0{appName}crwdnd38198:0{featureCommunity}crwdnd38198:0{appName}crwdne38198:0"
+ },
+ "blog": {
+ "title": "crwdns38200:0crwdne38200:0",
+ "description": "crwdns38202:0{appName}crwdnd38202:0{appName}crwdne38202:0"
+ }
+ }
+}
\ No newline at end of file
diff --git a/locales/cs.json b/locales/cs.json
new file mode 100644
index 0000000..d6d9b62
--- /dev/null
+++ b/locales/cs.json
@@ -0,0 +1,176 @@
+{
+ "feature": {
+ "accountIds": "ID účtů",
+ "nodes": "uzly",
+ "group": "Skupina",
+ "community": "Komunita"
+ },
+ "general": {
+ "download": "Stáhnout",
+ "whitepaper": "Whitepaper",
+ "litepaper": "Litepaper",
+ "messages": "Zprávy",
+ "metadata": "Metadata",
+ "privacyPolicy": "Zásady ochrany osobních údajů",
+ "termsOfService": "Podmínky služby",
+ "other": "Další"
+ },
+ "navigation": {
+ "blog": "Blog",
+ "resources": "Zdroje",
+ "docs": "Dokumenty",
+ "network": "Síť",
+ "help": "Nápověda",
+ "faq": "FAQ",
+ "support": "Podpora",
+ "aria": {
+ "whitepaper": "Odkaz na whitepaper {appName}",
+ "litepaper": "Odkaz na litepaper {appName}",
+ "sessionToken": "Odkaz na stránku tokenu {appName}",
+ "support": "Odkaz na podporu {appName} přes Zendesk",
+ "iconButtonOpen": "Otevřít navigační menu",
+ "iconButtonClose": "Zavřít navigační menu",
+ "downloadButton": "Odkaz na stažení {appName}"
+ }
+ },
+ "footer": {
+ "about": "Info",
+ "mediaKit": "Mediální sada",
+ "transparencyReport": "Zpráva o transparentnosti",
+ "foundation": "Nadace",
+ "appSupport": "Podpora {appName}",
+ "socials": "Sociální sítě",
+ "aria": {
+ "socialLink": "Odkaz na {appName} na {platform}",
+ "rssLink": "Odkaz na RSS kanál"
+ }
+ },
+ "languageSelection": {
+ "title": "Vyberte jazyk",
+ "description": "Vyberte svůj preferovaný jazyk ze seznamu níže",
+ "aria": {
+ "currentLanguage": "{language} (aktuální jazyk)",
+ "switchToLanguage": "Přepnout na {language}",
+ "currentLanguageIndicator": "(aktuální)"
+ }
+ },
+ "notFound": {
+ "pageNotFound": "Zdá se, že tato stránka neexistuje.",
+ "description": "Zdá se, že tento odkaz byl neplatný."
+ },
+ "email": {
+ "heading": "Každá aktualizace projektu přímo do vaší schránky.",
+ "subheading": "Očekávejte e-mail přibližně jednou měsíčně.",
+ "placeholder": "Váš e-mail",
+ "submitSuccessConfirm": "Díky! Zkontrolujte svou schránku a potvrďte odběr.",
+ "button": {
+ "text": "Přihlásit se"
+ },
+ "joinCommunity": "Připojte se k {appName} {featureCommunity} a potkejte živou komunitu lidí, kteří {appName} vyvíjejí, provozují a používají."
+ },
+ "landing": {
+ "hero": {
+ "heading": "Posílejte zprávy, ne metadata.",
+ "tag": "Objevte svobodu s {appName}",
+ "glitchTextGlitch": "Šifrováno"
+ },
+ "about": {
+ "title": "Co je {appName}?",
+ "content": "{appName} je koncově šifrovaný messenger, který chrání vaše osobní údaje. Znovu získejte kontrolu s aplikací navrženou, vytvořenou a provozovanou globální komunitou odborníků na soukromí ."
+ },
+ "benefits": {
+ "title": "Výhody",
+ "1": {
+ "heading": "Žádná telefonní čísla",
+ "content": "Chraňte svou identitu pomocí {featureAccountIds}. K registraci není třeba zadávat telefonní číslo ani e-mailovou adresu."
+ },
+ "2": {
+ "heading": "Žádné úniky dat",
+ "content": "{appName} neshromažďuje žádná data, takže nemá co uniknout."
+ },
+ "3": {
+ "heading": "Bezpečné cesty",
+ "content": "Trasy skrze Onion chrání vaše konverzace před hackery a odposlechy."
+ },
+ "4": {
+ "heading": "Otevřený zdrojový kód",
+ "content": "{appName} nemá co skrývat. Kdokoli může zobrazit, provést audit a přispět k jeho kódu. "
+ },
+ "5": {
+ "heading": "Síla komunity",
+ "content": "Tisíce {featureNodes} provozovaných globální komunitou. {appName} je od lidí, pro lidi."
+ },
+ "6": {
+ "heading": "Bez sledování",
+ "content": "Vaše data nejsou nikdy sbírána, sledována ani prodávána třetím stranám."
+ }
+ },
+ "features": {
+ "title": "Funkce",
+ "heading": "Užijte si oblíbené funkce a bezpečnost, kterou potřebujete.",
+ "1": {
+ "heading": "Mluvte svobodně",
+ "content": "Vaše zprávy vidíte jen vy a osoba, se kterou komunikujete. Užijte si pocit svobody díky end‑to‑end šifrování a mizejícím zprávám."
+ },
+ "2": {
+ "heading": "Mějte kontrolu",
+ "content": "Máte kontrolu nad svými zprávami od začátku do konce. Ať už jde o správu vlastních šifrovacích klíčů nebo výběr vlastního vzhledu—Session vám dává kontrolu."
+ },
+ "3": {
+ "heading": "Zůstaňte v kontaktu se skupinou",
+ "content": "Ať už doháníte novinky s přáteli nebo organizujete velkou akci, s bezpečnými {featureGroup} a {featureCommunity} (100+ členů) konverzacemi to jde snadno."
+ }
+ }
+ },
+ "redirect": {
+ "heading": "Přesměrování...",
+ "content": "Klikněte zde pro návrat na předchozí stránku."
+ },
+ "blog": {
+ "readMore": "Další informace",
+ "morePosts": "Další příspěvky"
+ },
+ "download": {
+ "heading": "Stáhněte si {appName} pro",
+ "mobile": "Mobil",
+ "desktop": "Počítač",
+ "verifySignatures": "Ověřte podpisy: {platforms}",
+ "releaseNotes": "Poznámky k vydání: {platforms}"
+ },
+ "imageAlt": {
+ "hero": "uživatelské rozhraní šifrované aplikace pro soukromé zprávy na mobilu",
+ "appLaptop": "šifrovaná aplikace pro soukromé zprávy běžící na MacBooku Pro",
+ "appMobile": "šifrovaná aplikace pro soukromé zprávy běžící na iPhonu"
+ },
+ "metadata": {
+ "default": {
+ "titleLayout": "{title} - {appName} Soukromý komunikátor",
+ "title": "{appName} | Posílejte zprávy, ne metadata. | Soukromý komunikátor",
+ "description": "{appName} je soukromý komunikátor, který se snaží znemožnit sběr metadat směrováním všech zpráv přes onion síť."
+ },
+ "download": {
+ "title": "Stáhnout",
+ "description": "Stáhněte si {appName} ještě dnes | {appName} je komunikátor s end-to-end šifrováním, který eliminuje sběr citlivých metadat pro všechny operační systémy."
+ },
+ "faq": {
+ "title": "Často kladené dotazy",
+ "description": "Najděte odpovědi na některé z nejčastěji kladených otázek týkajících se {appName}."
+ },
+ "litepaper": {
+ "description": "{appName} je decentralizovaný komunikátor, který podporuje zcela soukromou, bezpečnou a anonymní komunikaci.",
+ "title": "{appName} Litepaper: Posílejte zprávy, ne metadata"
+ },
+ "whitepaper": {
+ "description": "{appName} je decentralizovaný komunikátor, který podporuje zcela soukromou, bezpečnou a anonymní komunikaci.",
+ "title": "{appName} Whitepaper: Koncově šifrovaná komunikace s minimálním únikem metadat"
+ },
+ "community": {
+ "title": "{appName} {featureCommunity}",
+ "description": "Přidejte se k {appName} {featureCommunity} a poznejte živou komunitu lidí, kteří {appName} vytvářejí, provozují a používají."
+ },
+ "blog": {
+ "title": "Blog",
+ "description": "Prohlédněte si blogy {appName}. | {appName} je komunikátor s end‑to‑end šifrováním, který eliminuje sběr citlivých metadat."
+ }
+ }
+}
\ No newline at end of file
diff --git a/locales/de.json b/locales/de.json
new file mode 100644
index 0000000..1a3747c
--- /dev/null
+++ b/locales/de.json
@@ -0,0 +1,176 @@
+{
+ "feature": {
+ "accountIds": "Account-IDs",
+ "nodes": "Knoten",
+ "group": "Gruppe",
+ "community": "Community"
+ },
+ "general": {
+ "download": "Herunterladen",
+ "whitepaper": "Whitepaper",
+ "litepaper": "Litepaper",
+ "messages": "Nachrichten",
+ "metadata": "Metadaten",
+ "privacyPolicy": "Datenschutzerklärung",
+ "termsOfService": "Nutzungsbedingungen",
+ "other": "Sonstiges"
+ },
+ "navigation": {
+ "blog": "Blog",
+ "resources": "Ressourcen",
+ "docs": "Dokumentation",
+ "network": "Netzwerk",
+ "help": "Hilfe",
+ "faq": "Häufig gestellte Fragen (FAQ)",
+ "support": "Support",
+ "aria": {
+ "whitepaper": "Link zum {appName}-Whitepaper",
+ "litepaper": "Link zum {appName}-Litepaper",
+ "sessionToken": "Link zur Token-Website von {appName}",
+ "support": "Link zum {appName} Support über Zendesk",
+ "iconButtonOpen": "Navigationsmenü öffnen",
+ "iconButtonClose": "Navigationsmenü schließen",
+ "downloadButton": "Link zum Download von {appName}"
+ }
+ },
+ "footer": {
+ "about": "App-Info",
+ "mediaKit": "Medienkit",
+ "transparencyReport": "Transparenzbericht",
+ "foundation": "Stiftung",
+ "appSupport": "{appName} Support",
+ "socials": "Soziale Netzwerke",
+ "aria": {
+ "socialLink": "Link zu {appName} auf {platform}",
+ "rssLink": "Link zum RSS-Feed"
+ }
+ },
+ "languageSelection": {
+ "title": "Sprache wählen",
+ "description": "Wähle deine bevorzugte Sprache aus der Liste unten",
+ "aria": {
+ "currentLanguage": "{language} (aktuelle Sprache)",
+ "switchToLanguage": "Zu {language} wechseln",
+ "currentLanguageIndicator": "(aktuell)"
+ }
+ },
+ "notFound": {
+ "pageNotFound": "Diese Seite scheint nicht zu existieren.",
+ "description": "Es sieht so aus, als wäre der Link hierher fehlerhaft."
+ },
+ "email": {
+ "heading": "Jedes Projekt-Update direkt in deinen Posteingang.",
+ "subheading": "Etwa einmal im Monat erhältst du eine E-Mail.",
+ "placeholder": "Deine E-Mail",
+ "submitSuccessConfirm": "Danke! Überprüfe deinen Posteingang, um dein Abo zu bestätigen.",
+ "button": {
+ "text": "Registrieren"
+ },
+ "joinCommunity": "Tritt der {appName} {featureCommunity} bei und lerne die lebendige Community kennen, die Session entwickelt, betreibt und nutzt."
+ },
+ "landing": {
+ "hero": {
+ "heading": "Sende Nachrichten, Nicht Metadaten.",
+ "tag": "Finde deine Freiheit mit {appName}",
+ "glitchTextGlitch": "Verschlüsselt"
+ },
+ "about": {
+ "title": "Was ist {appName}?",
+ "content": "{appName} ist ein Ende-zu-Ende verschlüsselter Messenger, der deine persönlichen Daten schützt. Hol dir die Kontrolle zurück – mit einer Messaging-App, die von einer globalen Community aus Privatsphäre -Experten entworfen, entwickelt und betrieben wird."
+ },
+ "benefits": {
+ "title": "Vorteile",
+ "1": {
+ "heading": "Keine Rufnummern",
+ "content": "Schütze deine Identität mit {featureAccountIds}. Keine Telefonnummer oder E-Mail notwendig, um sich anzumelden."
+ },
+ "2": {
+ "heading": "Keine Datenlecks",
+ "content": "{appName} sammelt keine Daten, daher gibt es nichts, was geleakt werden kann."
+ },
+ "3": {
+ "heading": "Sichere Pfade",
+ "content": "Onion-geroutete Pfade schützen deine Gespräche vor Hackern und Abhörern."
+ },
+ "4": {
+ "heading": "Open Source",
+ "content": "{appName} Code hat nichts zu verbergen. Jeder kann ansehen, prüfen und beitragen. "
+ },
+ "5": {
+ "heading": "Von Leuten betrieben",
+ "content": "Tausende von {featureNodes}, betrieben von einer globalen Community. {appName} ist von den Menschen, für die Menschen."
+ },
+ "6": {
+ "heading": "Keine Tracker",
+ "content": "Deine Daten werden niemals gesammelt, niemals verfolgt und niemals an Dritte verkauft."
+ }
+ },
+ "features": {
+ "title": "Funktionen",
+ "heading": "Genieße die Funktionen, die du liebst, und die Sicherheit, die du brauchst.",
+ "1": {
+ "heading": "Sprich frei",
+ "content": "Nur du und die Person, mit der du sprichst, können deine Nachrichten sehen. Genieße das Gefühl von Freiheit mit Ende-zu-Ende-Verschlüsselung und selbstlöschenden Nachrichten."
+ },
+ "2": {
+ "heading": "Behalte die Kontrolle",
+ "content": "Du hast die volle Kontrolle über deine Nachrichten – vom Anfang bis zum Ende. Ob du deine eigenen Verschlüsselungsschlüssel verwaltest oder ein benutzerdefiniertes Design wählst – Session gibt dir die Kontrolle."
+ },
+ "3": {
+ "heading": "Bleib mit deiner Gruppe in Verbindung",
+ "content": "Egal ob du mit engen Freund*innen chattest oder ein großes Event organisierst – sichere {featureGroup}- und {featureCommunity}-Chats (100+ Mitglieder) machen es kinderleicht."
+ }
+ }
+ },
+ "redirect": {
+ "heading": "Weiterleitung...",
+ "content": "Klicke hier , um zur vorherigen Seite zurückzukehren."
+ },
+ "blog": {
+ "readMore": "Weiterlesen",
+ "morePosts": "Weitere Beiträge"
+ },
+ "download": {
+ "heading": "Lade {appName} herunter für",
+ "mobile": "Mobiles Gerät",
+ "desktop": "Desktop",
+ "verifySignatures": "Signaturen prüfen: {platforms}",
+ "releaseNotes": "Versionshinweise: {platforms}"
+ },
+ "imageAlt": {
+ "hero": "mobile verschlüsselte private Messaging-App UI-Vorschau",
+ "appLaptop": "verschlüsselte private Messaging-App, die auf einem Macbook Pro läuft",
+ "appMobile": "verschlüsselte private Messaging-App, die auf einem iPhone läuft"
+ },
+ "metadata": {
+ "default": {
+ "titleLayout": "{title} – {appName} Privater Messenger",
+ "title": "{appName} | Sende Nachrichten, Nicht Metadaten. | Privater Messenger",
+ "description": "{appName} ist ein privater Messenger, der versucht, jegliche Möglichkeit der Metadatenerfassung zu eliminieren, indem alle Nachrichten über ein Onion-Routing-Netzwerk geleitet werden."
+ },
+ "download": {
+ "title": "Herunterladen",
+ "description": "Lade {appName} noch heute herunter | {appName} ist ein Ende-zu-Ende-verschlüsselter Messenger, der die Erfassung sensibler Metadaten für alle Betriebssysteme verhindert."
+ },
+ "faq": {
+ "title": "Häufig gestellte Fragen (FAQ)",
+ "description": "Finde Antworten auf einige der am häufigsten gestellten Fragen zu {appName}."
+ },
+ "litepaper": {
+ "description": "{appName} ist ein dezentraler Messenger, der vollständig private, sichere und anonyme Kommunikation ermöglicht.",
+ "title": "{appName} Litepaper: Sende Nachrichten, keine Metadaten"
+ },
+ "whitepaper": {
+ "description": "{appName} ist ein dezentraler Messenger, der vollständig private, sichere und anonyme Kommunikation ermöglicht.",
+ "title": "{appName} Whitepaper: Ende-zu-Ende verschlüsselte Konversationen mit minimalem Leak von Metadaten"
+ },
+ "community": {
+ "title": "{appName} {featureCommunity}",
+ "description": "Tritt der {appName} {featureCommunity} bei und lerne die lebendige Community kennen, die {appName} entwickelt, betreibt und nutzt."
+ },
+ "blog": {
+ "title": "Blog",
+ "description": "Sieh dir die {appName}-Blogs an. | {appName} ist ein Ende-zu-Ende-verschlüsselter Messenger, der die Sammlung sensibler Metadaten eliminiert."
+ }
+ }
+}
\ No newline at end of file
diff --git a/locales/en.json b/locales/en.json
new file mode 100644
index 0000000..0e5c5ff
--- /dev/null
+++ b/locales/en.json
@@ -0,0 +1,176 @@
+{
+ "feature": {
+ "accountIds": "Account IDs",
+ "nodes": "nodes",
+ "group": "Group",
+ "community": "Community"
+ },
+ "general": {
+ "download": "Download",
+ "whitepaper": "Whitepaper",
+ "litepaper": "Litepaper",
+ "messages": "Messages",
+ "metadata": "Metadata",
+ "privacyPolicy": "Privacy Policy",
+ "termsOfService": "Terms of Service",
+ "other": "Other"
+ },
+ "navigation": {
+ "blog": "Blog",
+ "resources": "Resources",
+ "docs": "Docs",
+ "network": "Network",
+ "help": "Help",
+ "faq": "FAQ",
+ "support": "Support",
+ "aria": {
+ "whitepaper": "Link to {appName} Whitepaper",
+ "litepaper": "Link to {appName} Litepaper",
+ "sessionToken": "Link to {appName} Token website",
+ "support": "Link to {appName} Support via Zendesk",
+ "iconButtonOpen": "Open navigation menu",
+ "iconButtonClose": "Close navigation menu",
+ "downloadButton": "Link to {appName} download"
+ }
+ },
+ "footer": {
+ "about": "About",
+ "mediaKit": "Media Kit",
+ "transparencyReport": "Transparency Report",
+ "foundation": "Foundation",
+ "appSupport": "{appName} Support",
+ "socials": "Socials",
+ "aria": {
+ "socialLink": "Link to {appName} on {platform}",
+ "rssLink": "Link to RSS feed"
+ }
+ },
+ "languageSelection": {
+ "title": "Select your language",
+ "description": "Select your preferred language from the list below",
+ "aria": {
+ "currentLanguage": "{language} (current language)",
+ "switchToLanguage": "Switch to {language}",
+ "currentLanguageIndicator": "(current)"
+ }
+ },
+ "notFound": {
+ "pageNotFound": "This page doesn't seem to exist.",
+ "description": "It looks like the link pointing here was faulty."
+ },
+ "email": {
+ "heading": "Every update on digital privacy, delivered straight to your inbox.",
+ "subheading": "Expect an email about once a month.",
+ "placeholder": "Your Email",
+ "submitSuccessConfirm": "Thanks! Check your inbox to confirm your subscription.",
+ "button": {
+ "text": "Sign Up"
+ },
+ "joinCommunity": "Join the {appName} {featureCommunity} and meet the vibrant group of people building, running, and using Session."
+ },
+ "landing": {
+ "hero": {
+ "heading": "Send Messages, Not Metadata.",
+ "tag": "The decentralized private messaging app",
+ "glitchTextGlitch": "Encrypted"
+ },
+ "about": {
+ "title": "What is {appName}?",
+ "content": "{appName} is an end-to-end encrypted messenger that protects your private data. A decentralized app designed, built, and operated by a global community of privacy experts."
+ },
+ "benefits": {
+ "title": "Privacy Benefits",
+ "1": {
+ "heading": "No Phone Numbers",
+ "content": "Keep your identity private with Account IDs. No phone number or email required to sign up."
+ },
+ "2": {
+ "heading": "No Data Breaches",
+ "content": "{appName} doesn’t collect your private data, so there’s nothing to leak."
+ },
+ "3": {
+ "heading": "Safe Paths",
+ "content": "Onion-routed paths protect your conversations from hackers and eavesdroppers."
+ },
+ "4": {
+ "heading": "Open Source",
+ "content": "Privacy is more than a promise. Anyone can view, audit, and contribute to {appName}'s code."
+ },
+ "5": {
+ "heading": "People Powered",
+ "content": "Thousands of {featureNodes} run by a global community. {appName} is by the people, for the people."
+ },
+ "6": {
+ "heading": "No Trackers",
+ "content": "Your data is never collected, never tracked, and never sold to third parties."
+ }
+ },
+ "features": {
+ "title": "Features",
+ "heading": "Enjoy the features you love and the security you need.",
+ "1": {
+ "heading": "Speak freely",
+ "content": "Only you and the person you are speaking to can ever see your messages. Enjoy the feeling of freedom with end-to-end encryption and disappearing messages."
+ },
+ "2": {
+ "heading": "Stay in control",
+ "content": "You are in control of your messages from start to finish. Whether it’s managing your own encryption keys or choosing a custom theme—Session puts you in charge."
+ },
+ "3": {
+ "heading": "Privacy for your crowd",
+ "content": "Whether you’re catching up with close friends or organizing a major event, it’s effortless with secure {featureGroup} and {featureCommunity} (100+ members) chats."
+ }
+ }
+ },
+ "redirect": {
+ "heading": "Redirecting...",
+ "content": "Click here to return to the previous page."
+ },
+ "blog": {
+ "readMore": "Read More",
+ "morePosts": "More posts"
+ },
+ "download": {
+ "heading": "Download {appName} for",
+ "mobile": "Mobile",
+ "desktop": "Desktop",
+ "verifySignatures": "Verify Signatures: {platforms}",
+ "releaseNotes": "Release Notes: {platforms}"
+ },
+ "imageAlt": {
+ "hero": "mobile encrypted private messaging app ui showcase",
+ "appLaptop": "encrypted private messaging app running on a macbook pro",
+ "appMobile": "encrypted private messaging app running on an iphone"
+ },
+ "metadata": {
+ "default": {
+ "titleLayout": "{title} - {appName} Private Messenger",
+ "title": "{appName} | Send Messages, Not Metadata. | Private Messenger",
+ "description": "{appName} is a private messenger that aims to remove any chance of metadata collection by routing all messages through an onion routing network."
+ },
+ "download": {
+ "title": "Download",
+ "description": "Download {appName} Today | {appName} is an end-to-end encrypted messenger that removes sensitive metadata collection for all operating systems."
+ },
+ "faq": {
+ "title": "Frequently Asked Questions",
+ "description": "Find answers to some of the most frequently asked questions about {appName}."
+ },
+ "litepaper": {
+ "description": "{appName} is a decentralised messenger that supports completely private, secure, and anonymous communications.",
+ "title": "{appName} Litepaper: Send Messages, Not Metadata"
+ },
+ "whitepaper": {
+ "description": "{appName} is a decentralised messenger that supports completely private, secure, and anonymous communications.",
+ "title": "{appName} Whitepaper: End-To-End Encrypted Conversations with Minimal Metadata Leakage"
+ },
+ "community": {
+ "title": "{appName} {featureCommunity}",
+ "description": "Join the {appName} {featureCommunity} and meet the vibrant group of people building, running, and using {appName}."
+ },
+ "blog": {
+ "title": "Blog",
+ "description": "View the {appName} Blogs. | {appName} is an end-to-end encrypted messenger that removes sensitive metadata collection."
+ }
+ }
+}
\ No newline at end of file
diff --git a/locales/es.json b/locales/es.json
new file mode 100644
index 0000000..4fa24e1
--- /dev/null
+++ b/locales/es.json
@@ -0,0 +1,176 @@
+{
+ "feature": {
+ "accountIds": "ID de cuenta",
+ "nodes": "nodos",
+ "group": "Grupo",
+ "community": "Comunidad"
+ },
+ "general": {
+ "download": "Descargar",
+ "whitepaper": "Documento informativo",
+ "litepaper": "Documento resumido",
+ "messages": "Mensajes",
+ "metadata": "Metadatos",
+ "privacyPolicy": "Política de privacidad",
+ "termsOfService": "Términos del servicio",
+ "other": "Otro"
+ },
+ "navigation": {
+ "blog": "Blog",
+ "resources": "Recursos",
+ "docs": "Documentos",
+ "network": "Red",
+ "help": "Ayuda",
+ "faq": "Preguntas Frecuentes",
+ "support": "Soporte",
+ "aria": {
+ "whitepaper": "Enlace al Documento informativo de {appName}",
+ "litepaper": "Enlace al Documento resumido de {appName}",
+ "sessionToken": "Enlace al sitio web del Token de {appName}",
+ "support": "Enlace al Soporte de {appName} vía Zendesk",
+ "iconButtonOpen": "Abrir menú de navegación",
+ "iconButtonClose": "Cerrar menú de navegación",
+ "downloadButton": "Enlace para descargar {appName}"
+ }
+ },
+ "footer": {
+ "about": "Acerca de",
+ "mediaKit": "Kit de medios",
+ "transparencyReport": "Informe de transparencia",
+ "foundation": "Fundación",
+ "appSupport": "Soporte de {appName}",
+ "socials": "Redes sociales",
+ "aria": {
+ "socialLink": "Enlace a {appName} en {platform}",
+ "rssLink": "Enlace al canal RSS"
+ }
+ },
+ "languageSelection": {
+ "title": "Selecciona tu idioma",
+ "description": "Selecciona tu idioma preferido de la lista a continuación",
+ "aria": {
+ "currentLanguage": "{language} (idioma actual)",
+ "switchToLanguage": "Cambiar a {language}",
+ "currentLanguageIndicator": "(actual)"
+ }
+ },
+ "notFound": {
+ "pageNotFound": "Parece que esta página no existe.",
+ "description": "Parece que el enlace que apunta aquí es incorrecto."
+ },
+ "email": {
+ "heading": "Todas las actualizaciones del proyecto, directamente en tu bandeja de entrada.",
+ "subheading": "Recibirás un correo aproximadamente una vez al mes.",
+ "placeholder": "Tu correo electrónico",
+ "submitSuccessConfirm": "¡Gracias! Revisa tu bandeja de entrada para confirmar tu suscripción.",
+ "button": {
+ "text": "Registrarse"
+ },
+ "joinCommunity": "Únete a la {appName} {featureCommunity} y conoce al emocionante grupo de personas que construyen, operan y usan Session."
+ },
+ "landing": {
+ "hero": {
+ "heading": "Envía Mensajes, No Metadatos.",
+ "tag": "Encuentra tu libertad con {appName}",
+ "glitchTextGlitch": "Cifrado"
+ },
+ "about": {
+ "title": "¿Qué es {appName}?",
+ "content": "{appName} es una aplicación de mensajería con cifrado de extremo a extremo que protege tus datos personales . Recupera el control con una app de mensajería diseñada, desarrollada y operada por una comunidad global de expertos en privacidad ."
+ },
+ "benefits": {
+ "title": "Beneficios",
+ "1": {
+ "heading": "Sin números de teléfono",
+ "content": "Protege tu identidad con {featureAccountIds}. No es necesario ningún número de teléfono o correo electrónico para registrarte."
+ },
+ "2": {
+ "heading": "Sin filtraciones de datos",
+ "content": "{appName} no recopila datos, así que no hay nada que filtrar."
+ },
+ "3": {
+ "heading": "Rutas seguras",
+ "content": "Las rutas con enrutamiento en cebolla protegen tus conversaciones de hackers y espías."
+ },
+ "4": {
+ "heading": "Código abierto",
+ "content": "{appName} no tiene nada que ocultar. Cualquiera puede ver, examinar y contribuir a su código. "
+ },
+ "5": {
+ "heading": "Impulsado por la comunidad",
+ "content": "Miles de {featureNodes} gestionados por una comunidad global. {appName} está hecho por y para la comunidad."
+ },
+ "6": {
+ "heading": "Sin rastreadores",
+ "content": "Tus datos nunca se recopilan, nunca se rastrean, y nunca se venden a terceros."
+ }
+ },
+ "features": {
+ "title": "Características",
+ "heading": "Disfruta de las funciones que te encantan y de la seguridad que necesitas.",
+ "1": {
+ "heading": "Habla libremente",
+ "content": "Solo tú y la persona con la que hablas pueden ver tus mensajes. Disfruta la sensación de libertad con cifrado de extremo a extremo y mensajes que desaparecen."
+ },
+ "2": {
+ "heading": "Mantén el control",
+ "content": "Tienes el control de tus mensajes de principio a fin. Ya sea administrando tus propias claves de cifrado o eligiendo un tema personalizado—Session te pone al mando."
+ },
+ "3": {
+ "heading": "Sigue el ritmo de tu grupo",
+ "content": "Ya sea poniéndote al día con amigos cercanos u organizando un gran evento, es fácil con chats seguros de {featureGroup} y {featureCommunity} (100+ miembros)."
+ }
+ }
+ },
+ "redirect": {
+ "heading": "Redirigiendo...",
+ "content": "Haz clic aquí para volver a la página anterior."
+ },
+ "blog": {
+ "readMore": "Leer Más",
+ "morePosts": "Más publicaciones"
+ },
+ "download": {
+ "heading": "Descargar {appName} para",
+ "mobile": "Móvil",
+ "desktop": "Escritorio",
+ "verifySignatures": "Verificar firmas: {platforms}",
+ "releaseNotes": "Notas de la versión: {platforms}"
+ },
+ "imageAlt": {
+ "hero": "interfaz de app de mensajería privada cifrada en el móvil",
+ "appLaptop": "app de mensajería privada cifrada ejecutándose en una MacBook Pro",
+ "appMobile": "app de mensajería privada cifrada ejecutándose en un iPhone"
+ },
+ "metadata": {
+ "default": {
+ "titleLayout": "{title} - {appName} Mensajero Privado",
+ "title": "{appName} | Envía Mensajes, no Metadatos. | Mensajería Privada",
+ "description": "{appName} es una app de mensajería privada que busca eliminar cualquier posibilidad de recopilación de metadatos, enrutando todos los mensajes a través de una red con enrutamiento en cebolla."
+ },
+ "download": {
+ "title": "Descargar",
+ "description": "Descarga {appName} hoy | {appName} es una app de mensajería cifrada de extremo a extremo que elimina la recopilación de metadatos sensibles para todos los sistemas operativos."
+ },
+ "faq": {
+ "title": "Preguntas Frecuentes",
+ "description": "Encuentra respuestas a algunas de las preguntas más frecuentes sobre {appName}."
+ },
+ "litepaper": {
+ "description": "{appName} es una app de mensajería descentralizada que admite comunicaciones completamente privadas, seguras y anónimas.",
+ "title": "Documento resumido de {appName}: Envía mensajes, no metadatos"
+ },
+ "whitepaper": {
+ "description": "{appName} es una app de mensajería descentralizada que admite comunicaciones completamente privadas, seguras y anónimas.",
+ "title": "Documento informativo de {appName}: Conversaciones cifradas de extremo a extremo minimizando la filtración de metadatos"
+ },
+ "community": {
+ "title": "{appName} {featureCommunity}",
+ "description": "Únete a la {featureCommunity} de {appName} y conoce al emocionante grupo de personas que construyen, ejecutan y usan {appName}."
+ },
+ "blog": {
+ "title": "Blog",
+ "description": "Consulta los blogs de {appName}. | {appName} es una app de mensajería cifrada de extremo a extremo que elimina la recopilación de metadatos sensibles."
+ }
+ }
+}
\ No newline at end of file
diff --git a/locales/fr.json b/locales/fr.json
new file mode 100644
index 0000000..618c990
--- /dev/null
+++ b/locales/fr.json
@@ -0,0 +1,176 @@
+{
+ "feature": {
+ "accountIds": "ID du compte",
+ "nodes": "nœuds",
+ "group": "Groupe",
+ "community": "Communauté"
+ },
+ "general": {
+ "download": "Télécharger",
+ "whitepaper": "Livre blanc",
+ "litepaper": "Litepaper",
+ "messages": "Messages",
+ "metadata": "Métadonnées",
+ "privacyPolicy": "Politique de confidentialité",
+ "termsOfService": "Conditions d'utilisation",
+ "other": "Autre"
+ },
+ "navigation": {
+ "blog": "Blog",
+ "resources": "Ressources",
+ "docs": "Docs",
+ "network": "Réseau",
+ "help": "Aide",
+ "faq": "FAQ",
+ "support": "Assistance",
+ "aria": {
+ "whitepaper": "Lien vers le livre blanc de {appName}",
+ "litepaper": "Lien vers le litepaper de {appName}",
+ "sessionToken": "Lien vers le site du Token {appName}",
+ "support": "Lien vers l’assistance {appName} via Zendesk",
+ "iconButtonOpen": "Ouvrir le menu de navigation",
+ "iconButtonClose": "Fermer le menu de navigation",
+ "downloadButton": "Lien pour télécharger {appName}"
+ }
+ },
+ "footer": {
+ "about": "À propos",
+ "mediaKit": "Kit médias",
+ "transparencyReport": "Rapport de transparence",
+ "foundation": "Fondation",
+ "appSupport": "Assistance {appName}",
+ "socials": "Réseaux sociaux",
+ "aria": {
+ "socialLink": "Lien vers {appName} sur {platform}",
+ "rssLink": "Lien vers le fil RSS"
+ }
+ },
+ "languageSelection": {
+ "title": "Choisissez votre langue",
+ "description": "Sélectionnez votre langue préférée dans la liste ci-dessous",
+ "aria": {
+ "currentLanguage": "{language} (langue actuelle)",
+ "switchToLanguage": "Basculer en {language}",
+ "currentLanguageIndicator": "(actuel)"
+ }
+ },
+ "notFound": {
+ "pageNotFound": "Cette page ne semble pas exister.",
+ "description": "Il semble que le lien pointant ici soit défectueux."
+ },
+ "email": {
+ "heading": "Chaque mise à jour de projet, directement dans votre boîte de réception.",
+ "subheading": "Vous recevrez environ un email par mois.",
+ "placeholder": "Votre adresse email",
+ "submitSuccessConfirm": "Merci ! Vérifiez votre boîte de réception pour confirmer votre abonnement.",
+ "button": {
+ "text": "S'inscrire"
+ },
+ "joinCommunity": "Rejoignez la communauté {featureCommunity} de {appName} et rencontrez le groupe dynamique de personnes qui créent, gèrent et utilisent Session."
+ },
+ "landing": {
+ "hero": {
+ "heading": "Envoyez des messages, pas des métadonnées.",
+ "tag": "Trouvez votre liberté avec {appName}",
+ "glitchTextGlitch": "Chiffrés"
+ },
+ "about": {
+ "title": "Qu'est-ce que {appName} ?",
+ "content": "{appName} est une messagerie chiffrée de bout en bout qui protège vos données personnelles . Reprenez le contrôle avec une application de messagerie conçue, développée et exploitée par une communauté mondiale d'experts en confidentialité ."
+ },
+ "benefits": {
+ "title": "Avantages",
+ "1": {
+ "heading": "Aucun numéro de téléphone",
+ "content": "Protégez votre identité avec un {featureAccountIds}. Aucun numéro ou e-mail requis."
+ },
+ "2": {
+ "heading": "Aucune fuite de données",
+ "content": "{appName} ne collecte pas de données, donc rien ne peut être divulgué."
+ },
+ "3": {
+ "heading": "Chemins sécurisés",
+ "content": "Les chemins à routage en oignon protègent vos conversations des pirates et des traqueurs."
+ },
+ "4": {
+ "heading": "Open Source",
+ "content": "{appName} n'a rien à cacher. Tout le mode peut voir, contrôler et contribuer à son code. "
+ },
+ "5": {
+ "heading": "Par les utilisateurs",
+ "content": "Des milliers de {featureNodes} gérés par une communauté mondiale. {appName} est fait par le peuple, pour le peuple."
+ },
+ "6": {
+ "heading": "Aucun traceur",
+ "content": "Vos données ne sont jamais collectées, jamais suivies, et jamais revendues à des tiers."
+ }
+ },
+ "features": {
+ "title": "Fonctionnalités",
+ "heading": "Profitez des fonctionnalités que vous aimez et de la sécurité qu’il vous faut.",
+ "1": {
+ "heading": "Parlez librement",
+ "content": "Seuls vous et votre interlocuteur pouvez voir vos messages. Soyez libre grâce au chiffrement de bout en bout et aux messages éphémères."
+ },
+ "2": {
+ "heading": "Gardez le contrôle",
+ "content": "Restez en contrôle de vos messages du début à la fin. Qu’il s’agisse de gérer vos propres clés de chiffrement ou de choisir un thème personnalisé — Session vous met aux commandes."
+ },
+ "3": {
+ "heading": "Restez connecté avec votre communauté",
+ "content": "Que vous retrouviez des amis proches ou organisiez un grand événement, c’est simple avec des discussions {featureGroup} et {featureCommunity} (100+ membres) sécurisées."
+ }
+ }
+ },
+ "redirect": {
+ "heading": "Redirection...",
+ "content": "Cliquez ici pour revenir à la page précédente."
+ },
+ "blog": {
+ "readMore": "En savoir plus",
+ "morePosts": "Autres articles"
+ },
+ "download": {
+ "heading": "Télécharger {appName} pour",
+ "mobile": "Smartphone",
+ "desktop": "Ordinateur",
+ "verifySignatures": "Vérifier les signatures : {platforms}",
+ "releaseNotes": "Notes de version : {platforms}"
+ },
+ "imageAlt": {
+ "hero": "interface d’une application de messagerie privée chiffrée sur mobile",
+ "appLaptop": "application de messagerie privée chiffrée fonctionnant sur un MacBook Pro",
+ "appMobile": "application de messagerie privée chiffrée fonctionnant sur un iPhone"
+ },
+ "metadata": {
+ "default": {
+ "titleLayout": "{title} - Messagerie privée {appName}",
+ "title": "{appName} | Envoyez des messages, pas des métadonnées. | Messagerie privée",
+ "description": "{appName} est une messagerie privée qui vise à empêcher toute collecte de métadonnées en relayant tous les messages via un réseau de routage en oignon."
+ },
+ "download": {
+ "title": "Télécharger",
+ "description": "Téléchargez {appName} dès aujourd’hui | {appName} est une messagerie chiffrée de bout en bout qui empêche la collecte de métadonnées sensibles pour tous les systèmes d’exploitation."
+ },
+ "faq": {
+ "title": "Foire Aux Questions",
+ "description": "Trouvez les réponses aux questions les plus fréquemment posées à propos de {appName}."
+ },
+ "litepaper": {
+ "description": "{appName} est une messagerie décentralisée qui permet des communications entièrement privées, sécurisées et anonymes.",
+ "title": "{appName} Litepaper : Envoyez des messages, pas des métadonnées"
+ },
+ "whitepaper": {
+ "description": "{appName} est une messagerie décentralisée qui permet des communications entièrement privées, sécurisées et anonymes.",
+ "title": "{appName} Livre blanc : Conversations chiffrées de bout en bout avec fuite de métadonnées minimales"
+ },
+ "community": {
+ "title": "{appName} {featureCommunity}",
+ "description": "Rejoignez la {featureCommunity} de {appName} et découvrez un groupe dynamique de personnes construisant, exploitant et utilisant {appName}."
+ },
+ "blog": {
+ "title": "Blog",
+ "description": "Consultez les articles de blog de {appName}. | {appName} est une messagerie chiffrée de bout en bout qui empêche la collecte de métadonnées sensibles."
+ }
+ }
+}
\ No newline at end of file
diff --git a/locales/hi.json b/locales/hi.json
new file mode 100644
index 0000000..fe88cbd
--- /dev/null
+++ b/locales/hi.json
@@ -0,0 +1,176 @@
+{
+ "feature": {
+ "accountIds": "अकाउंट ID",
+ "nodes": "नोड्स",
+ "group": "समूह",
+ "community": "समुदाय"
+ },
+ "general": {
+ "download": "डाउनलोड करें",
+ "whitepaper": "वाइटपेपर",
+ "litepaper": "लाइटपेपर",
+ "messages": "मेसेज",
+ "metadata": "मेटाडेटा",
+ "privacyPolicy": "गोपनीयता नीति",
+ "termsOfService": "सेवा की शर्तें",
+ "other": "अन्य"
+ },
+ "navigation": {
+ "blog": "ब्लॉग",
+ "resources": "संसाधन",
+ "docs": "डॉक्स",
+ "network": "नेटवर्क",
+ "help": "मदद",
+ "faq": "अक्सर पूछे जाने वाले सवाल",
+ "support": "सहायता",
+ "aria": {
+ "whitepaper": "{appName} वाइटपेपर का लिंक",
+ "litepaper": "{appName} लाइटपेपर का लिंक",
+ "sessionToken": "{appName} टोकन वेबसाइट लिंक",
+ "support": "{appName} सहायता लिंक (Zendesk के माध्यम से)",
+ "iconButtonOpen": "नेविगेशन मेनू खोलें",
+ "iconButtonClose": "नेविगेशन मेनू बंद करें",
+ "downloadButton": "{appName} डाउनलोड लिंक"
+ }
+ },
+ "footer": {
+ "about": "हमारे बारे में",
+ "mediaKit": "मीडियाकिट",
+ "transparencyReport": "पारदर्शिता रिपोर्ट",
+ "foundation": "फ़ाउंडेशन",
+ "appSupport": "{appName} सहायता",
+ "socials": "सोशल मीडिया",
+ "aria": {
+ "socialLink": "{platform} पर {appName} का लिंक",
+ "rssLink": "RSS फ़ीड का लिंक"
+ }
+ },
+ "languageSelection": {
+ "title": "अपनी भाषा चुनें",
+ "description": "नीचे दी गई सूची से अपनी पसंदीदा भाषा चुनें।",
+ "aria": {
+ "currentLanguage": "{language} (वर्तमान भाषा)",
+ "switchToLanguage": "{language} बदलें",
+ "currentLanguageIndicator": "(वर्तमान)"
+ }
+ },
+ "notFound": {
+ "pageNotFound": "शायद यह पेज अब उपलब्ध नहीं है।",
+ "description": "लगता है यहां दिया गया लिंक गलत था।"
+ },
+ "email": {
+ "heading": "हर प्रोजेक्ट अपडेट, सीधे आपके इनबॉक्स में।",
+ "subheading": "हर महीने बस एक ईमेल आएगा।",
+ "placeholder": "आपका ईमेल",
+ "submitSuccessConfirm": "शुक्रिया! सदस्यता पक्की करने के लिए अपना इनबॉक्स ज़रूर देखें।",
+ "button": {
+ "text": "साइन अप करें"
+ },
+ "joinCommunity": "{appName} {featureCommunity} से जुड़ें और उन लोगों से मिलें जो Session को बना रहे हैं, चला रहे हैं और इस्तेमाल कर रहे हैं।\n"
+ },
+ "landing": {
+ "hero": {
+ "heading": "संदेश भेजें, मेटाडेटा नहीं।",
+ "tag": "अपनी आज़ादी पाएं, {appName} के साथ\n",
+ "glitchTextGlitch": "एन्क्रिप्टेड"
+ },
+ "about": {
+ "title": "{appName} क्या है?",
+ "content": "{appName} एक एंड-टू-एंड एन्क्रिप्टेड मैसेंजर है जो आपके व्यक्तिगत डेटा की सुरक्षा करता है। एक वैश्विक प्राइवेसी विशेषज्ञों के समुदाय द्वारा डिज़ाइन, निर्मित और संचालित मैसेजिंग ऐप के साथ नियंत्रण वापस लें।"
+ },
+ "benefits": {
+ "title": "लाभ",
+ "1": {
+ "heading": "कोई फोन नंबर नहीं",
+ "content": "{featureAccountIds} के साथ अपनी पहचान सुरक्षित रखें। साइन अप करने के लिए न फोन नंबर चाहिए, न ईमेल।"
+ },
+ "2": {
+ "heading": "कोई डेटा उल्लंघन नहीं",
+ "content": "{appName} डेटा एकत्र नहीं करता, इसलिए लीक होने लायक कुछ नहीं है।"
+ },
+ "3": {
+ "heading": "सुरक्षित रास्ते",
+ "content": "ओनियन-रूटेड रास्ते आपके संवादों को हैकर्स और जासूसों से सुरक्षित रखते हैं।"
+ },
+ "4": {
+ "heading": "ओपन सोर्स",
+ "content": "{appName} कुछ नहीं छुपाता। कोई भी इसका कोड देख सकता है, ऑडिट कर सकता है और उसमें योगदान दे सकता है "
+ },
+ "5": {
+ "heading": "लोगों द्वारा संचालित",
+ "content": "{featureNodes} की हजारों इकाइयाँ एक वैश्विक समुदाय द्वारा चलाई जाती हैं। {appName} लोगों के द्वारा, लोगों के लिए है।"
+ },
+ "6": {
+ "heading": "कोई ट्रैकर नहीं",
+ "content": "आपका डेटा कभी एकत्र नहीं किया जाता, ट्रैक नहीं किया जाता, और कभी भी तीसरे पक्ष को बेचा नहीं जाता।"
+ }
+ },
+ "features": {
+ "title": "विशेषताएँ",
+ "heading": "आपकी पसंदीदा विशेषताओं और आवश्यक सुरक्षा का आनंद लें।",
+ "1": {
+ "heading": "स्वतंत्र रूप से बात करें",
+ "content": "केवल आप और जिससे आप बात कर रहे हैं वही आपके संदेश देख सकते हैं। एंड-टू-एंड एन्क्रिप्शन और गायब होने वाले संदेशों के साथ स्वतंत्रता की भावना का आनंद लें।"
+ },
+ "2": {
+ "heading": "नियंत्रण बनाए रखें",
+ "content": "आप शुरुआत से अंत तक अपने संदेशों पर नियंत्रण रखते हैं। चाहे वह आपकी एन्क्रिप्शन कुंजियाँ प्रबंधित करना हो या कस्टम थीम चुनना—Session आपको नियंत्रण प्रदान करता है।"
+ },
+ "3": {
+ "heading": "अपनी भीड़ के साथ जुड़े रहें",
+ "content": "चाहे आप अपने करीबी दोस्तों से संपर्क में हों या कोई बड़ा कार्यक्रम आयोजन कर रहे हों, सुरक्षित {featureGroup} और {featureCommunity} (100+ सदस्य) चैट्स के साथ यह सरल है।"
+ }
+ }
+ },
+ "redirect": {
+ "heading": "पुनः निर्देशित किया जा रहा है...",
+ "content": "पिछले पृष्ठ पर लौटने के लिए यहाँ क्लिक करें ।"
+ },
+ "blog": {
+ "readMore": "और पढ़ें",
+ "morePosts": "अधिक पोस्ट्स"
+ },
+ "download": {
+ "heading": "{appName} डाउनलोड करें",
+ "mobile": "मोबाइल",
+ "desktop": "डेस्कटॉप",
+ "verifySignatures": "हस्ताक्षर सत्यापित करें: {platforms}",
+ "releaseNotes": "रिलीज़ नोट्स: {platforms}"
+ },
+ "imageAlt": {
+ "hero": "मोबाइल एन्क्रिप्टेड प्राइवेट मैसेजिंग ऐप यूआई शोकेस",
+ "appLaptop": "एक मैकबुक प्रो पर चलता हुआ एन्क्रिप्टेड प्राइवेट मैसेजिंग ऐप",
+ "appMobile": "एक iPhone पर चलता हुआ एन्क्रिप्टेड प्राइवेट मैसेजिंग ऐप"
+ },
+ "metadata": {
+ "default": {
+ "titleLayout": "{title} - {appName} प्राइवेट मैसेंजर",
+ "title": "{appName} | संदेश भेजें, मेटाडेटा नहीं। | प्राइवेट मैसेंजर",
+ "description": "{appName} एक निजी मैसेंजर है जो सभी संदेशों को ओनियन रूटिंग नेटवर्क के माध्यम से प्रेषित कर किसी भी प्रकार की मेटाडेटा एकत्र करने की संभावना को समाप्त करता है।"
+ },
+ "download": {
+ "title": "डाउनलोड",
+ "description": "आज ही {appName} डाउनलोड करें | {appName} एक एंड-टू-एंड एन्क्रिप्टेड मैसेंजर है जो सभी ऑपरेटिंग सिस्टम्स के लिए संवेदनशील मेटाडेटा संग्रहण को हटाता है।"
+ },
+ "faq": {
+ "title": "अकसर किये गए सवाल",
+ "description": "{appName} से जुड़े कुछ सबसे अधिक पूछे जाने वाले प्रश्नों के उत्तर जानें।"
+ },
+ "litepaper": {
+ "description": "{appName} एक विकेंद्रीकृत मैसेंजर है जो पूर्ण रूप से निजी, सुरक्षित और गुमनाम संवाद का समर्थन करता है।",
+ "title": "{appName} लाइटपेपर: मैसेज भेजें, मेटाडेटा नहीं"
+ },
+ "whitepaper": {
+ "description": "{appName} एक विकेंद्रीकृत मैसेंजर है जो पूर्ण रूप से निजी, सुरक्षित और गुमनाम संवाद का समर्थन करता है।",
+ "title": "{appName} व्हाइटपेपर: एंड-टू-एंड एन्क्रिप्टेड बातचीत, न्यूनतम मेटाडेटा लीक के साथ"
+ },
+ "community": {
+ "title": "{appName} {featureCommunity}",
+ "description": "{appName} {featureCommunity} से जुड़ें और उन लोगों से मिलें जो {appName} का निर्माण, संचालन और उपयोग कर रहे हैं।"
+ },
+ "blog": {
+ "title": "ब्लॉग",
+ "description": "{appName} ब्लॉग्स देखें। | {appName} एक एंड-टू-एंड एन्क्रिप्टेड मैसेंजर है जो संवेदनशील मेटाडेटा संग्रहण को हटाता है।"
+ }
+ }
+}
\ No newline at end of file
diff --git a/locales/hu.json b/locales/hu.json
new file mode 100644
index 0000000..0d34b43
--- /dev/null
+++ b/locales/hu.json
@@ -0,0 +1,176 @@
+{
+ "feature": {
+ "accountIds": "Fiókazonosítók",
+ "nodes": "csomópontok",
+ "group": "Csoport",
+ "community": "Közösség"
+ },
+ "general": {
+ "download": "Letöltés",
+ "whitepaper": "Fehér könyv",
+ "litepaper": "Litepaper",
+ "messages": "Üzenetek",
+ "metadata": "Metaadatok",
+ "privacyPolicy": "Adatvédelmi szabályzat",
+ "termsOfService": "Szolgáltatási feltételek",
+ "other": "Egyéb"
+ },
+ "navigation": {
+ "blog": "Blog",
+ "resources": "Erőforrások",
+ "docs": "Dokumentáció",
+ "network": "Hálózat",
+ "help": "Segítség",
+ "faq": "GYIK",
+ "support": "Támogatás",
+ "aria": {
+ "whitepaper": "Hivatkozás a(z) {appName} fehér könyvére",
+ "litepaper": "Hivatkozás a(z) {appName} litepaperére",
+ "sessionToken": "Hivatkozás a(z) {appName} token weboldalára",
+ "support": "Kapcsolat a(z) {appName} ügyfélszolgálattal a Zendesk-en keresztül",
+ "iconButtonOpen": "Navigációs menü megnyitása",
+ "iconButtonClose": "Navigációs menü bezárása",
+ "downloadButton": "Hivatkozás a(z) {appName} letöltéséhez"
+ }
+ },
+ "footer": {
+ "about": "Névjegy",
+ "mediaKit": "Médiacsomag",
+ "transparencyReport": "Átláthatósági jelentés",
+ "foundation": "Alapítvány",
+ "appSupport": "{appName} támogatás",
+ "socials": "Közösségi oldalak",
+ "aria": {
+ "socialLink": "Hivatkozás a(z) {platform} oldalán elérhető {appName}-re",
+ "rssLink": "Hivatkozás az RSS-hírcsatornára"
+ }
+ },
+ "languageSelection": {
+ "title": "Válaszd ki a nyelved",
+ "description": "Válaszd ki az alábbi listából a kívánt nyelvet",
+ "aria": {
+ "currentLanguage": "{language} (jelenlegi nyelv)",
+ "switchToLanguage": "Váltás erre: {language}",
+ "currentLanguageIndicator": "(jelenleg)"
+ }
+ },
+ "notFound": {
+ "pageNotFound": "Úgy tűnik, ez az oldal nem létezik.",
+ "description": "Úgy tűnik, hogy a hivatkozás hibás volt."
+ },
+ "email": {
+ "heading": "Minden projektfrissítés, közvetlenül az e-mail fiókodba.",
+ "subheading": "Körülbelül havonta egyszer számíthatsz egy e-mailre.",
+ "placeholder": "E-mail címed",
+ "submitSuccessConfirm": "Köszönjük! Ellenőrizd postafiókodat a feliratkozás megerősítéséhez.",
+ "button": {
+ "text": "Feliratkozás"
+ },
+ "joinCommunity": "Csatlakozz a {appName} {featureCommunity} közösséghez, és ismerd meg azokat az embereket, akik építik, működtetik és használják a Sessiont."
+ },
+ "landing": {
+ "hero": {
+ "heading": "Send Messages, Not Metadata.",
+ "tag": "Találd meg a szabadságodat a(z) {appName} segítségével",
+ "glitchTextGlitch": "Titkosítva"
+ },
+ "about": {
+ "title": "Mi az a {appName}?",
+ "content": "A(z) {appName} egy végponttól végpontig titkosított üzenetküldő alkalmazás, amely védi a személyes adataidat. Szerezd vissza az irányítást egy olyan üzenetküldő alkalmazással, amelyet egy világszintű adatvédelmi szakértőkből álló közösség tervezett, fejlesztett és üzemeltet."
+ },
+ "benefits": {
+ "title": "Előnyök",
+ "1": {
+ "heading": "Nincs telefonszám",
+ "content": "Protect your identity with {featureAccountIds}. No phone number or email required to sign up."
+ },
+ "2": {
+ "heading": "Nincsenek adatszivárgások",
+ "content": "A(z) {appName} nem gyűjt adatokat, így nincs mit kiszivárogtatni."
+ },
+ "3": {
+ "heading": "Biztonságos útvonalak",
+ "content": "A hagymahálózaton keresztüli útvonalak védik a beszélgetéseidet a hackerekkel és lehallgatókkal szemben."
+ },
+ "4": {
+ "heading": "Nyílt forráskódú",
+ "content": "{appName} has nothing to hide. Anyone can view, audit, and contribute to its code. "
+ },
+ "5": {
+ "heading": "Közösségi működtetésű",
+ "content": "Több ezer {featureNodes} működik világszerte egy globális közösség által. A(z) {appName} emberek által, embereknek készült."
+ },
+ "6": {
+ "heading": "Nincsenek követők",
+ "content": "Az adataidat sosem gyűjtjük, nem követjük nyomon, és sosem adjuk el harmadik feleknek."
+ }
+ },
+ "features": {
+ "title": "Funkciók",
+ "heading": "Élvezd a kedvenc funkcióidat és a szükséges biztonságot.",
+ "1": {
+ "heading": "Beszélj szabadon",
+ "content": "Csak te és a beszélgetőpartnered láthatjátok az üzeneteket. Élvezd a szabadság érzését végpontok közötti titkosítással és eltűnő üzenetekkel."
+ },
+ "2": {
+ "heading": "Maradj irányítás alatt",
+ "content": "Az üzeneteid teljes mértékben a te irányításod alatt állnak. Legyen szó a saját titkosítási kulcsaid kezeléséről vagy egyedi téma kiválasztásáról – a Session nálad hagyja az irányítást."
+ },
+ "3": {
+ "heading": "Tartsd a lépést a társaságoddal",
+ "content": "Akár barátokkal csevegsz vagy nagyszabású eseményt szervezel, biztonságos {featureGroup} és {featureCommunity} (100+ tag) csevegésekkel mindez gyerekjáték."
+ }
+ }
+ },
+ "redirect": {
+ "heading": "Átirányítás...",
+ "content": "Kattints ide az előző oldalra való visszatéréshez."
+ },
+ "blog": {
+ "readMore": "Részletek",
+ "morePosts": "További bejegyzések"
+ },
+ "download": {
+ "heading": "Töltsd le a(z) {appName} alkalmazást",
+ "mobile": "Mobil",
+ "desktop": "Asztali gép",
+ "verifySignatures": "Aláírások ellenőrzése: {platforms}",
+ "releaseNotes": "Kiadási megjegyzések: {platforms}"
+ },
+ "imageAlt": {
+ "hero": "mobil titkosított privát üzenetküldő alkalmazás felhasználói felület bemutató",
+ "appLaptop": "titkosított privát üzenetküldő alkalmazás MacBook Pro-n fut",
+ "appMobile": "titkosított privát üzenetküldő alkalmazás iPhone-on fut"
+ },
+ "metadata": {
+ "default": {
+ "titleLayout": "{title} – {appName} Privát Messenger",
+ "title": "{appName} | Küldj üzeneteket, ne metaadatokat. | Privát Messenger",
+ "description": "A(z) {appName} egy privát üzenetküldő, amely célja, hogy megszüntesse a metaadatok gyűjtésének lehetőségét azáltal, hogy minden üzenetet hagymahálózaton keresztül továbbít."
+ },
+ "download": {
+ "title": "Letöltés",
+ "description": "Töltsd le a(z) {appName} még ma | A(z) {appName} egy végpontok között titkosított üzenetküldő, amely minden operációs rendszeren kiküszöböli az érzékeny metaadatok gyűjtését."
+ },
+ "faq": {
+ "title": "Gyakran Ismételt Kérdések",
+ "description": "Find answers to some of the most frequently asked questions about {appName}."
+ },
+ "litepaper": {
+ "description": "A(z) {appName} egy decentralizált üzenetküldő, amely teljesen privát, biztonságos és névtelen kommunikációt tesz lehetővé.",
+ "title": "{appName} Litepaper: Send Messages, Not Metadata"
+ },
+ "whitepaper": {
+ "description": "A(z) {appName} egy decentralizált üzenetküldő, amely teljesen privát, biztonságos és névtelen kommunikációt tesz lehetővé.",
+ "title": "{appName} Whitepaper: End-To-End Encrypted Conversations with Minimal Metadata Leakage"
+ },
+ "community": {
+ "title": "{appName} {featureCommunity}",
+ "description": "Csatlakozz a(z) {appName} {featureCommunity} közösségéhez, és ismerd meg azt az élénk közösséget, amely építi, működteti és használja a(z) {appName} alkalmazást."
+ },
+ "blog": {
+ "title": "Blog",
+ "description": "Tekintsd meg a(z) {appName} blogokat. | A(z) {appName} egy végpontok között titkosított üzenetküldő, amely kiküszöböli az érzékeny metaadatok gyűjtését."
+ }
+ }
+}
\ No newline at end of file
diff --git a/locales/it.json b/locales/it.json
new file mode 100644
index 0000000..4412405
--- /dev/null
+++ b/locales/it.json
@@ -0,0 +1,176 @@
+{
+ "feature": {
+ "accountIds": "ID account",
+ "nodes": "nodi",
+ "group": "Gruppo",
+ "community": "Comunità"
+ },
+ "general": {
+ "download": "Scarica",
+ "whitepaper": "Whitepaper",
+ "litepaper": "Litepaper",
+ "messages": "Messaggi",
+ "metadata": "Metadati",
+ "privacyPolicy": "Politica sulla privacy",
+ "termsOfService": "Termini e condizioni",
+ "other": "Altro"
+ },
+ "navigation": {
+ "blog": "Blog",
+ "resources": "Risorse",
+ "docs": "Documentazione",
+ "network": "Rete",
+ "help": "Aiuto",
+ "faq": "Domande frequenti",
+ "support": "Assistenza",
+ "aria": {
+ "whitepaper": "Link al whitepaper di {appName}",
+ "litepaper": "Link al litepaper di {appName}",
+ "sessionToken": "Link al sito web del token di {appName}",
+ "support": "Link all'assistenza di {appName} tramite Zendesk",
+ "iconButtonOpen": "Apri il menu di navigazione",
+ "iconButtonClose": "Chiudi il menu di navigazione",
+ "downloadButton": "Link per scaricare {appName}"
+ }
+ },
+ "footer": {
+ "about": "Informazioni",
+ "mediaKit": "Media kit",
+ "transparencyReport": "Rapporto sulla trasparenza",
+ "foundation": "Fondazione",
+ "appSupport": "Assistenza {appName}",
+ "socials": "Social",
+ "aria": {
+ "socialLink": "Link a {appName} su {platform}",
+ "rssLink": "Link al feed RSS"
+ }
+ },
+ "languageSelection": {
+ "title": "Seleziona la tua lingua",
+ "description": "Seleziona la lingua preferita dall'elenco qui sotto",
+ "aria": {
+ "currentLanguage": "{language} (lingua attuale)",
+ "switchToLanguage": "Passa a {language}",
+ "currentLanguageIndicator": "(attuale)"
+ }
+ },
+ "notFound": {
+ "pageNotFound": "Questa pagina sembra non esistere.",
+ "description": "Sembra che il link che indirizzava qui fosse errato."
+ },
+ "email": {
+ "heading": "Ogni aggiornamento del progetto, direttamente nella tua casella di posta.",
+ "subheading": "Riceverai circa un'email al mese.",
+ "placeholder": "La tua email",
+ "submitSuccessConfirm": "Grazie! Controlla la tua casella di posta per confermare l'iscrizione.",
+ "button": {
+ "text": "Iscriviti"
+ },
+ "joinCommunity": "Unisciti alla {featureCommunity} {appName} e incontra il gruppo vivace di persone che costruiscono, gestiscono e usano Session."
+ },
+ "landing": {
+ "hero": {
+ "heading": "Invia messaggi, non metadati.",
+ "tag": "Trova la tua libertà con {appName}",
+ "glitchTextGlitch": "Crittografati"
+ },
+ "about": {
+ "title": "Cos'è {appName}?",
+ "content": "{appName} è un'app di messaggistica crittografata end-to-end che protegge i tuoi dati personali . Riprendi il controllo con un'app progettata, costruita e gestita da una comunità globale di esperti della privacy ."
+ },
+ "benefits": {
+ "title": "Vantaggi",
+ "1": {
+ "heading": "Nessun numero di telefono",
+ "content": "Proteggi la tua identità con {featureAccountIds}. Non è richiesto alcun numero di telefono o email per registrarsi."
+ },
+ "2": {
+ "heading": "Nessuna violazione dei dati",
+ "content": "{appName} non raccoglie dati, quindi non è possibile nessuna violazione."
+ },
+ "3": {
+ "heading": "Percorsi sicuri",
+ "content": "I percorsi instradati tramite onion proteggono le tue conversazioni da hacker e intercettazioni."
+ },
+ "4": {
+ "heading": "Open source",
+ "content": "{appName} non ha nulla da nascondere. Chiunque può visualizzare, verificare e contribuire al suo codice. "
+ },
+ "5": {
+ "heading": "Supportato dalle persone",
+ "content": "Migliaia di {featureNodes} gestiti da una comunità globale. {appName} è fatto dalle persone per le persone."
+ },
+ "6": {
+ "heading": "Nessun tracciamento",
+ "content": "I tuoi dati non vengono mai raccolti, mai tracciati e mai venduti a terze parti."
+ }
+ },
+ "features": {
+ "title": "Funzionalità",
+ "heading": "Approfitta delle funzionalità che preferisci e della sicurezza di cui hai bisogno.",
+ "1": {
+ "heading": "Parla liberamente",
+ "content": "Solo tu e la persona con cui parli potete vedere i vostri messaggi. Prova la sensazione di libertà con crittografia end-to-end e messaggi che scompaiono."
+ },
+ "2": {
+ "heading": "Rimani al comando",
+ "content": "Hai il controllo dei tuoi messaggi dall'inizio alla fine. A prescindere che si tratti di gestire le chiavi di crittografia o scegliere un tema personalizzato, Session ti mette al comando."
+ },
+ "3": {
+ "heading": "Resta in contatto con il tuo gruppo",
+ "content": "Indipendentemente che tu stia chiacchierando con amici intimi o organizzando un grande evento, tutto è più facile con le chat sicure di {featureGroup} e {featureCommunity} (oltre 100 membri)."
+ }
+ }
+ },
+ "redirect": {
+ "heading": "Reindirizzamento...",
+ "content": "Clicca qui per tornare alla pagina precedente."
+ },
+ "blog": {
+ "readMore": "Scopri di più",
+ "morePosts": "Altri articoli"
+ },
+ "download": {
+ "heading": "Scarica {appName} per",
+ "mobile": "Mobile",
+ "desktop": "Desktop",
+ "verifySignatures": "Verifica firme: {platforms}",
+ "releaseNotes": "Note sulla versione: {platforms}"
+ },
+ "imageAlt": {
+ "hero": "interfaccia utente dell'app di messaggistica privata criptata su cellulare",
+ "appLaptop": "app di messaggistica privata criptata in esecuzione su un MacBook Pro",
+ "appMobile": "app di messaggistica privata criptata in esecuzione su un iPhone"
+ },
+ "metadata": {
+ "default": {
+ "titleLayout": "{title} - {appName} Messenger Privato",
+ "title": "{appName} | Invia Messaggi, Non Metadati. | Messenger Privato",
+ "description": "{appName} è un messenger privato che mira a eliminare ogni possibilità di raccolta di metadati instradando tutti i messaggi tramite una rete onion."
+ },
+ "download": {
+ "title": "Scarica",
+ "description": "Scarica {appName} oggi stesso | {appName} è un messenger criptato end-to-end che elimina la raccolta di metadati sensibili per tutti i sistemi operativi."
+ },
+ "faq": {
+ "title": "Domande frequenti",
+ "description": "Trova risposte ad alcune delle domande più frequenti su {appName}."
+ },
+ "litepaper": {
+ "description": "{appName} è un messenger decentralizzato che supporta comunicazioni completamente private, sicure e anonime.",
+ "title": "Litepaper di {appName}: invia messaggi, non metadati"
+ },
+ "whitepaper": {
+ "description": "{appName} è un messenger decentralizzato che supporta comunicazioni completamente private, sicure e anonime.",
+ "title": "Whitepaper di {appName}: conversazioni crittografate end-to-end che minimizzano la perdita di metadati"
+ },
+ "community": {
+ "title": "{featureCommunity} {appName}",
+ "description": "Unisciti alla {featureCommunity} {appName} e incontra il vivace gruppo di persone che costruiscono, gestiscono e usano {appName}."
+ },
+ "blog": {
+ "title": "Blog",
+ "description": "Consulta i blog di {appName}. | {appName} è un messenger criptato end-to-end che elimina la raccolta di metadati sensibili."
+ }
+ }
+}
\ No newline at end of file
diff --git a/locales/ja.json b/locales/ja.json
new file mode 100644
index 0000000..24dbe3d
--- /dev/null
+++ b/locales/ja.json
@@ -0,0 +1,176 @@
+{
+ "feature": {
+ "accountIds": "アカウント ID",
+ "nodes": "ノード",
+ "group": "グループ",
+ "community": "コミュニティ"
+ },
+ "general": {
+ "download": "ダウンロード",
+ "whitepaper": "ホワイトペーパー",
+ "litepaper": "ライトペーパー",
+ "messages": "メッセージ",
+ "metadata": "メタデータ",
+ "privacyPolicy": "プライバシーポリシー",
+ "termsOfService": "利用規約",
+ "other": "その他"
+ },
+ "navigation": {
+ "blog": "ブログ",
+ "resources": "リソース",
+ "docs": "ドキュメント",
+ "network": "ネットワーク",
+ "help": "ヘルプ",
+ "faq": "よくある質問",
+ "support": "サポート",
+ "aria": {
+ "whitepaper": "{appName}のホワイトペーパーへのリンク",
+ "litepaper": "{appName}のライトペーパーへのリンク",
+ "sessionToken": "{appName}のトークンサイトへのリンク",
+ "support": "Zendesk経由の{appName}サポートへのリンク",
+ "iconButtonOpen": "ナビゲーションメニューを開く",
+ "iconButtonClose": "ナビゲーションメニューを閉じる",
+ "downloadButton": "{appName}のダウンロードへのリンク"
+ }
+ },
+ "footer": {
+ "about": "情報",
+ "mediaKit": "メディアキット",
+ "transparencyReport": "透明性レポート",
+ "foundation": "ファウンデーション",
+ "appSupport": "{appName}サポート",
+ "socials": "ソーシャル",
+ "aria": {
+ "socialLink": "{platform}上の{appName}へのリンク",
+ "rssLink": "RSSフィードへのリンク"
+ }
+ },
+ "languageSelection": {
+ "title": "言語を選択",
+ "description": "下記のリストからご希望の言語を選択してください",
+ "aria": {
+ "currentLanguage": "{language}(現在の言語)",
+ "switchToLanguage": "{language}に切り替える",
+ "currentLanguageIndicator": "(現在)"
+ }
+ },
+ "notFound": {
+ "pageNotFound": "このページは存在しないようです。",
+ "description": "ここへのリンクが無効のようです。"
+ },
+ "email": {
+ "heading": "すべてのプロジェクト更新情報を、直接メールでお届けします。",
+ "subheading": "およそ月に1回、メールをお送りします。",
+ "placeholder": "メールアドレス",
+ "submitSuccessConfirm": "ありがとうございます!購読確認のメールを受信トレイでご確認ください。",
+ "button": {
+ "text": "登録する"
+ },
+ "joinCommunity": "{appName} {featureCommunity} に参加して、Sessionを構築・運用・使用する活気あるコミュニティと出会いましょう。"
+ },
+ "landing": {
+ "hero": {
+ "heading": "メッセージ を送信し、メタデータは送信しないでください。",
+ "tag": "{appName}で自由を見つけよう",
+ "glitchTextGlitch": "暗号化"
+ },
+ "about": {
+ "title": "{appName}とは?",
+ "content": "{appName}は、あなたの個人 データを保護するエンドツーエンド の暗号化メッセンジャーです。プライバシー の専門家によるグローバル なコミュニティによって設計・開発・運営されたメッセージングアプリで、コントロールを取り戻しましょう。"
+ },
+ "benefits": {
+ "title": "利点",
+ "1": {
+ "heading": "電話番号なし",
+ "content": "{featureAccountIds} であなたの身元を保護。 電話番号やメールアドレスなしで登録できます。"
+ },
+ "2": {
+ "heading": "データ漏洩なし",
+ "content": "{appName}はデータを収集しないため、 漏洩するものがありません。"
+ },
+ "3": {
+ "heading": "安全な経路",
+ "content": "オニオンルーティング経由の経路が ハッカーや盗聴者から会話を守ります。"
+ },
+ "4": {
+ "heading": "オープンソース",
+ "content": "{appName} は隠すものがありません。 誰でもコードを閲覧・監査・貢献できます。 "
+ },
+ "5": {
+ "heading": "人々による運営",
+ "content": "世界中のコミュニティによって運営されている{featureNodes}が何千も存在します。 {appName}は人々のために、人々によって作られています。"
+ },
+ "6": {
+ "heading": "トラッカーなし",
+ "content": "あなたのデータは収集されず、追跡されず、 第三者に販売されることもありません。"
+ }
+ },
+ "features": {
+ "title": "機能",
+ "heading": "あなたの好きな機能と必要なセキュリティを両立。",
+ "1": {
+ "heading": "自由に話そう",
+ "content": "あなたと相手だけがメッセージを見ることができます。エンドツーエンド暗号化とメッセージの自動消去で自由を実感しましょう。"
+ },
+ "2": {
+ "heading": "自分で管理",
+ "content": "あなたのメッセージは最初から最後まであなたが管理します。暗号鍵の管理からテーマのカスタマイズまで — Sessionがコントロールをあなたに委ねます。"
+ },
+ "3": {
+ "heading": "仲間とつながろう",
+ "content": "親しい友人との近況報告でも、大規模イベントの運営でも、セキュアな{featureGroup}チャットや100人以上対応の{featureCommunity}チャットで簡単に実現できます。"
+ }
+ }
+ },
+ "redirect": {
+ "heading": "リダイレクト中...",
+ "content": "こちら をクリックして前のページへ戻ってください。"
+ },
+ "blog": {
+ "readMore": "続きを読む",
+ "morePosts": "他の記事"
+ },
+ "download": {
+ "heading": "{appName}をダウンロード",
+ "mobile": "携帯",
+ "desktop": "デスクトップ",
+ "verifySignatures": "署名を検証:{platforms}",
+ "releaseNotes": "リリースノート:{platforms}"
+ },
+ "imageAlt": {
+ "hero": "モバイル暗号化プライベートメッセージングアプリのUIショーケース",
+ "appLaptop": "MacBook Proで動作中の暗号化プライベートメッセージングアプリ",
+ "appMobile": "iPhoneで動作中の暗号化プライベートメッセージングアプリ"
+ },
+ "metadata": {
+ "default": {
+ "titleLayout": "{title} - {appName} プライベートメッセンジャー",
+ "title": "{appName} | メッセージを送信、メタデータではなく。 | プライベートメッセンジャー",
+ "description": "{appName}は、すべてのメッセージをオニオンルーティングネットワークを通じて送信することでメタデータ収集の可能性を排除することを目的としたプライベートメッセンジャーです。"
+ },
+ "download": {
+ "title": "ダウンロード",
+ "description": "今すぐ{appName}をダウンロード | {appName}は機密メタデータの収集を排除するエンドツーエンド暗号化メッセンジャーです。すべてのOSに対応。"
+ },
+ "faq": {
+ "title": "よくある質問",
+ "description": "{appName} に関するよくあるご質問とその回答をご覧いただけます。"
+ },
+ "litepaper": {
+ "description": "{appName}は完全にプライベートで安全、そして匿名性の高い通信を提供する分散型メッセンジャーです。",
+ "title": "{appName} Litepaper:送るのはメッセージであり、メタデータではありません"
+ },
+ "whitepaper": {
+ "description": "{appName}は完全にプライベートで安全、そして匿名性の高い通信を提供する分散型メッセンジャーです。",
+ "title": "{appName} ホワイトペーパー:エンドツーエンド暗号化による会話と、最小限のメタデータ漏えい"
+ },
+ "community": {
+ "title": "{appName} {featureCommunity}",
+ "description": "{appName}の{featureCommunity}に参加して、{appName}を構築・運営・利用している活気あるコミュニティメンバーと出会いましょう。"
+ },
+ "blog": {
+ "title": "ブログ",
+ "description": "{appName}のブログを表示。| {appName}は機密メタデータ収集を排除するエンドツーエンド暗号化メッセンジャーです。"
+ }
+ }
+}
\ No newline at end of file
diff --git a/locales/nl.json b/locales/nl.json
new file mode 100644
index 0000000..dff7a33
--- /dev/null
+++ b/locales/nl.json
@@ -0,0 +1,176 @@
+{
+ "feature": {
+ "accountIds": "Account-ID's",
+ "nodes": "nodes",
+ "group": "Groep",
+ "community": "Community"
+ },
+ "general": {
+ "download": "Downloaden",
+ "whitepaper": "Whitepaper",
+ "litepaper": "Litepaper",
+ "messages": "Berichten",
+ "metadata": "Metadata",
+ "privacyPolicy": "Privacybeleid",
+ "termsOfService": "Gebruiksvoorwaarden",
+ "other": "Overige"
+ },
+ "navigation": {
+ "blog": "Blog",
+ "resources": "Bronnen",
+ "docs": "Documentatie",
+ "network": "Netwerk",
+ "help": "Help",
+ "faq": "Veelgestelde vragen",
+ "support": "Helpdesk",
+ "aria": {
+ "whitepaper": "Link naar {appName} Whitepaper",
+ "litepaper": "Link naar {appName} Litepaper",
+ "sessionToken": "Link naar {appName} Token-website",
+ "support": "Link naar {appName} helpdesk via Zendesk",
+ "iconButtonOpen": "Navigatiemenu openen",
+ "iconButtonClose": "Navigatiemenu sluiten",
+ "downloadButton": "Link naar {appName}-download"
+ }
+ },
+ "footer": {
+ "about": "Over",
+ "mediaKit": "Mediakit",
+ "transparencyReport": "Transparantierapport",
+ "foundation": "Stichting",
+ "appSupport": "{appName} Helpdesk",
+ "socials": "Socials",
+ "aria": {
+ "socialLink": "Link naar {appName} op {platform}",
+ "rssLink": "Link naar RSS-feed"
+ }
+ },
+ "languageSelection": {
+ "title": "Selecteer je taal",
+ "description": "Selecteer je voorkeurstaal uit de onderstaande lijst",
+ "aria": {
+ "currentLanguage": "{language} (huidige taal)",
+ "switchToLanguage": "Overschakelen naar {language}",
+ "currentLanguageIndicator": "(momenteel)"
+ }
+ },
+ "notFound": {
+ "pageNotFound": "Deze pagina lijkt niet te bestaan.",
+ "description": "De link naar deze pagina lijkt niet te werken."
+ },
+ "email": {
+ "heading": "Alle projectupdates rechtstreeks in je inbox.",
+ "subheading": "Verwacht ongeveer één e-mail per maand.",
+ "placeholder": "Je e-mailadres",
+ "submitSuccessConfirm": "Bedankt! Controleer je inbox om je abonnement te bevestigen.",
+ "button": {
+ "text": "Inschrijven"
+ },
+ "joinCommunity": "Word lid van de {appName} {featureCommunity} en maak kennis met de bruisende community die Session ontwikkelt, beheert en gebruikt."
+ },
+ "landing": {
+ "hero": {
+ "heading": "Verstuur berichten, geen metadata.",
+ "tag": "Vind je vrijheid met {appName}",
+ "glitchTextGlitch": "Versleuteld"
+ },
+ "about": {
+ "title": "Wat is {appName}?",
+ "content": "{appName} is een end-to-end versleutelde messenger die jouw persoonlijke gegevens beschermt. Herpak de controle met een berichtenapp die is ontworpen, gebouwd en beheerd door een wereldwijde community van privacy -experts."
+ },
+ "benefits": {
+ "title": "Voordelen",
+ "1": {
+ "heading": "Geen telefoonnummers",
+ "content": "Bescherm je identiteit met {featureAccountIds}. Je hebt geen telefoonnummer of e-mailadres nodig om je aan te melden."
+ },
+ "2": {
+ "heading": "Geen datalekken",
+ "content": "{appName} verzamelt geen gegevens, dus er is niets dat gelekt kan worden."
+ },
+ "3": {
+ "heading": "Veilige paden",
+ "content": "Onion-gerouteerde paden beschermen je gesprekken tegen hackers en afluisteraars."
+ },
+ "4": {
+ "heading": "Open source",
+ "content": "{appName} heeft niets te verbergen. Iedereen kan de code bekijken, controleren en eraan bijdragen. "
+ },
+ "5": {
+ "heading": "Gedreven door mensen",
+ "content": "Duizenden {featureNodes} worden beheerd door een wereldwijde community. {appName} is door de mensen, voor de mensen."
+ },
+ "6": {
+ "heading": "Geen trackers",
+ "content": "Jouw gegevens worden nooit verzameld, nooit gevolgd en nooit verkocht aan derden."
+ }
+ },
+ "features": {
+ "title": "Functies",
+ "heading": "Geniet van de functies die je leuk vindt en de beveiliging die je nodig hebt.",
+ "1": {
+ "heading": "Spreek vrijuit",
+ "content": "Je berichten zijn alleen zichtbaar voor jou en degene met wie je praat. Ervaar echte vrijheid dankzij end-to-end encryptie en verdwijnende berichten."
+ },
+ "2": {
+ "heading": "Behoud de controle",
+ "content": "Jij hebt de controle over je berichten van begin tot eind. Of het nu gaat om het beheren van je eigen versleutelingssleutels of het kiezen van een aangepast thema—Session geeft jou de touwtjes in handen."
+ },
+ "3": {
+ "heading": "Blijf in contact met jouw community",
+ "content": "Of je nu bijpraat met goede vrienden of een groot evenement organiseert, met beveiligde {featureGroup}- en {featureCommunity}-chats (100+ leden) doe je dat eenvoudig en veilig."
+ }
+ }
+ },
+ "redirect": {
+ "heading": "Doorsturen...",
+ "content": "Klik hier om terug te gaan naar de vorige pagina."
+ },
+ "blog": {
+ "readMore": "Lees meer",
+ "morePosts": "Meer berichten"
+ },
+ "download": {
+ "heading": "Download {appName} voor",
+ "mobile": "Mobiel",
+ "desktop": "Desktop",
+ "verifySignatures": "Handtekeningen verifiëren: {platforms}",
+ "releaseNotes": "Versie-opmerkingen: {platforms}"
+ },
+ "imageAlt": {
+ "hero": "mobiele versleutelde privéberichten-app UI-weergave",
+ "appLaptop": "versleutelde privéberichten-app draaiend op een MacBook Pro",
+ "appMobile": "versleutelde privéberichten-app draaiend op een iPhone"
+ },
+ "metadata": {
+ "default": {
+ "titleLayout": "{title} - {appName} Privé Messenger",
+ "title": "{appName} | Verstuur berichten, geen metadata. | Privé Messenger",
+ "description": "{appName} is een privé messenger die elke kans op het verzamelen van metadata wil uitsluiten door alle berichten via een onion-routingnetwerk te versturen."
+ },
+ "download": {
+ "title": "Downloaden",
+ "description": "Download {appName} vandaag nog | {appName} is een end-to-end versleutelde messenger die het verzamelen van gevoelige metadata op elk besturingssysteem uitsluit."
+ },
+ "faq": {
+ "title": "Veelgestelde vragen (FAQ)",
+ "description": "Vind antwoorden op de meest gestelde vragen over {appName}."
+ },
+ "litepaper": {
+ "description": "{appName} is een gedecentraliseerde messenger die volledig privé, veilig en anoniem communiceren ondersteunt.",
+ "title": "{appName} Litepaper: Verstuur berichten, geen metadata"
+ },
+ "whitepaper": {
+ "description": "{appName} is een gedecentraliseerde messenger die volledig privé, veilig en anoniem communiceren ondersteunt.",
+ "title": "{appName} Whitepaper: End-to-end versleutelde gesprekken met minimale metadata-lekkage"
+ },
+ "community": {
+ "title": "{appName} {featureCommunity}",
+ "description": "Word lid van de {appName} {featureCommunity} en maak kennis met de bruisende community die {appName} ontwikkelt, beheert en gebruikt."
+ },
+ "blog": {
+ "title": "Blog",
+ "description": "Bekijk de {appName} Blogs. | {appName} is een end-to-end versleutelde messenger die het verzamelen van gevoelige metadata uitsluit."
+ }
+ }
+}
\ No newline at end of file
diff --git a/locales/pl.json b/locales/pl.json
new file mode 100644
index 0000000..7e0c119
--- /dev/null
+++ b/locales/pl.json
@@ -0,0 +1,176 @@
+{
+ "feature": {
+ "accountIds": "identyfikatorom kont",
+ "nodes": "węzłów",
+ "group": "Grupa",
+ "community": "Społeczność"
+ },
+ "general": {
+ "download": "Pobierz",
+ "whitepaper": "Whitepaper",
+ "litepaper": "Litepaper",
+ "messages": "Wiadomości",
+ "metadata": "Metadane",
+ "privacyPolicy": "Polityka prywatności",
+ "termsOfService": "Warunki korzystania z usługi",
+ "other": "Inne"
+ },
+ "navigation": {
+ "blog": "Blog",
+ "resources": "Zasoby",
+ "docs": "Dokumentacja",
+ "network": "Sieć",
+ "help": "Pomoc",
+ "faq": "FAQ",
+ "support": "Wsparcie",
+ "aria": {
+ "whitepaper": "Link do Whitepaper {appName}",
+ "litepaper": "Link do Litepaper {appName}",
+ "sessionToken": "Link do strony tokena {appName}",
+ "support": "Link do wsparcia {appName} przez Zendesk",
+ "iconButtonOpen": "Otwórz menu nawigacyjne",
+ "iconButtonClose": "Zamknij menu nawigacyjne",
+ "downloadButton": "Link do pobrania {appName}"
+ }
+ },
+ "footer": {
+ "about": "O aplikacji",
+ "mediaKit": "Informacje dla prasy",
+ "transparencyReport": "Raport o przejrzystości",
+ "foundation": "Fundacja",
+ "appSupport": "Wsparcie techniczne {appName}",
+ "socials": "Społeczności",
+ "aria": {
+ "socialLink": "Link do {appName} na {platform}",
+ "rssLink": "Link do kanału RSS"
+ }
+ },
+ "languageSelection": {
+ "title": "Wybierz swój język",
+ "description": "Wybierz preferowany język z poniższej listy",
+ "aria": {
+ "currentLanguage": "{language} (aktualny język)",
+ "switchToLanguage": "Przełącz na {language}",
+ "currentLanguageIndicator": "(obecnie)"
+ }
+ },
+ "notFound": {
+ "pageNotFound": "Ta strona wygląda na nieistniejącą.",
+ "description": "Wygląda na to, że link kierujący tutaj był nieprawidłowy."
+ },
+ "email": {
+ "heading": "Każda aktualizacja projektu — bezpośrednio do Twojej skrzynki odbiorczej.",
+ "subheading": "Spodziewaj się wiadomości e-mail raz w miesiącu.",
+ "placeholder": "Twój e-mail",
+ "submitSuccessConfirm": "Dzięki! Sprawdź skrzynkę odbiorczą, aby potwierdzić subskrypcję.",
+ "button": {
+ "text": "Zapisz się"
+ },
+ "joinCommunity": "Dołącz do {appName} {featureCommunity} i poznaj dynamiczną społeczność budującą, obsługującą i używającą Session."
+ },
+ "landing": {
+ "hero": {
+ "heading": "Wysyłaj Wiadomości, Nie Metadane.",
+ "tag": "Odzyskaj wolność z {appName}",
+ "glitchTextGlitch": "Szyfrowane"
+ },
+ "about": {
+ "title": "Czym jest {appName}?",
+ "content": "{appName} to komunikator z szyfrowaniem end-to-end , który chroni Twoje dane osobowe . Odzyskaj kontrolę dzięki aplikacji stworzonej, zaprojektowanej i prowadzonej przez globalną społeczność ekspertów ds. prywatności ."
+ },
+ "benefits": {
+ "title": "Korzyści",
+ "1": {
+ "heading": "Bez numerów telefonów",
+ "content": "Chroń swoją tożsamość dzięki {featureAccountIds}. Do rejestracji nie jest wymagany numer telefonu ani adres e-mail."
+ },
+ "2": {
+ "heading": "Bez wycieków danych",
+ "content": "{appName} nie gromadzi danych, więc nie ma co wyciekać."
+ },
+ "3": {
+ "heading": "Bezpieczne ścieżki",
+ "content": "Ścieżki oparte na technologii onion chronią Twoje rozmowy przed hakerami i podsłuchiwaczami."
+ },
+ "4": {
+ "heading": "Open Source",
+ "content": "{appName} nie ma nic do ukrycia. Każdy może przeglądać, sprawdzać i współtworzyć jego kod. "
+ },
+ "5": {
+ "heading": "Siła społeczności",
+ "content": "Tysiące {featureNodes} obsługiwanych przez globalną społeczność. {appName} należy do ludzi i jest dla ludzi."
+ },
+ "6": {
+ "heading": "Brak trackerów",
+ "content": "Twoje dane nigdy nie są zbierane, śledzone ani sprzedawane osobom trzecim."
+ }
+ },
+ "features": {
+ "title": "Funkcje",
+ "heading": "Ciesz się funkcjami, które lubisz, i bezpieczeństwem, na które zasługujesz.",
+ "1": {
+ "heading": "Rozmawiaj swobodnie",
+ "content": "Tylko Ty i osoba, z którą rozmawiasz, możecie zobaczyć swoje wiadomości. Ciesz się poczuciem wolności dzięki szyfrowaniu end-to-end i znikającym wiadomościom."
+ },
+ "2": {
+ "heading": "Zachowaj kontrolę",
+ "content": "Masz pełną kontrolę nad swoimi wiadomościami od początku do końca. Niezależnie od tego, czy jest to zarządzanie własnymi kluczami szyfrowania, czy wybór własnego motywu — Session daje Ci pełną kontrolę."
+ },
+ "3": {
+ "heading": "Bądź na bieżąco ze swoimi znajomymi",
+ "content": "Niezależnie od tego, czy nadrabiasz zaległości z bliskimi znajomymi, czy organizujesz duże wydarzenie, z bezpiecznymi czatami typu {featureGroup} oraz {featureCommunity} (100+ członków) jest to czysta przyjemność."
+ }
+ }
+ },
+ "redirect": {
+ "heading": "Przekierowywanie...",
+ "content": "Kliknij tutaj , aby wrócić do poprzedniej strony."
+ },
+ "blog": {
+ "readMore": "Czytaj więcej",
+ "morePosts": "Więcej postów"
+ },
+ "download": {
+ "heading": "Pobierz {appName} na",
+ "mobile": "Telefon",
+ "desktop": "Komputer",
+ "verifySignatures": "Weryfikuj podpisy: {platforms}",
+ "releaseNotes": "Informacje o wersji: {platforms}"
+ },
+ "imageAlt": {
+ "hero": "interfejs graficzny aplikacji mobilnej do prywatnej komunikacji szyfrowanej",
+ "appLaptop": "aplikacja do szyfrowanej prywatnej komunikacji działająca na MacBooku Pro",
+ "appMobile": "aplikacja do szyfrowanej prywatnej komunikacji działająca na iPhonie"
+ },
+ "metadata": {
+ "default": {
+ "titleLayout": "{title} - Prywatny komunikator {appName}",
+ "title": "{appName} | Wysyłaj wiadomości, nie metadane. | Prywatny komunikator",
+ "description": "{appName} to prywatny komunikator, który eliminuje możliwość zbierania metadanych, przekierowując wszystkie wiadomości przez sieć typu onion."
+ },
+ "download": {
+ "title": "Pobierz",
+ "description": "Pobierz {appName} już dziś | {appName} to komunikator z szyfrowaniem end-to-end, który eliminuje zbieranie wrażliwych metadanych na wszystkich systemach operacyjnych."
+ },
+ "faq": {
+ "title": "Najczęściej zadawane pytania",
+ "description": "Zobacz odpowiedzi na najczęściej zadawane pytania dotyczące {appName}."
+ },
+ "litepaper": {
+ "description": "{appName} to zdecentralizowany komunikator wspierający całkowicie prywatną, bezpieczną i anonimową komunikację.",
+ "title": "{appName} Litepaper: Wysyłaj Wiadomości, Nie Metadane"
+ },
+ "whitepaper": {
+ "description": "{appName} to zdecentralizowany komunikator wspierający całkowicie prywatną, bezpieczną i anonimową komunikację.",
+ "title": "{appName} Whitepaper: Rozmowy Szyfrowane End-To-End z Minimalnym Ujawnianiem Metadanych"
+ },
+ "community": {
+ "title": "{featureCommunity} {appName}",
+ "description": "Dołącz do {featureCommunity} {appName} i poznaj dynamiczną społeczność ludzi, którzy tworzą, rozwijają i używają {appName}."
+ },
+ "blog": {
+ "title": "Blog",
+ "description": "Zobacz blogi {appName}. | {appName} to komunikator z szyfrowaniem end-to-end, który usuwa zbieranie wrażliwych metadanych."
+ }
+ }
+}
\ No newline at end of file
diff --git a/locales/pt.json b/locales/pt.json
new file mode 100644
index 0000000..aa22cbb
--- /dev/null
+++ b/locales/pt.json
@@ -0,0 +1,176 @@
+{
+ "feature": {
+ "accountIds": "IDs de Conta",
+ "nodes": "nós",
+ "group": "Grupo",
+ "community": "Comunidade"
+ },
+ "general": {
+ "download": "Transferir",
+ "whitepaper": "Whitepaper",
+ "litepaper": "Litepaper",
+ "messages": "Mensagens",
+ "metadata": "Metadados",
+ "privacyPolicy": "Política de Privacidade",
+ "termsOfService": "Termos de Serviço",
+ "other": "Outro"
+ },
+ "navigation": {
+ "blog": "Blogue",
+ "resources": "Recursos",
+ "docs": "Documentos",
+ "network": "Rede",
+ "help": "Ajuda",
+ "faq": "FAQ (Perguntas Mais Frequentes)",
+ "support": "Suporte",
+ "aria": {
+ "whitepaper": "Ligação para o Whitepaper de {appName}",
+ "litepaper": "Ligação para o Litepaper de {appName}",
+ "sessionToken": "Ligação para o site do Token de {appName}",
+ "support": "Ligação para o Suporte de {appName} via Zendesk",
+ "iconButtonOpen": "Abrir menu de navegação",
+ "iconButtonClose": "Fechar menu de navegação",
+ "downloadButton": "Ligação para a transferência de {appName}"
+ }
+ },
+ "footer": {
+ "about": "Sobre",
+ "mediaKit": "Kit de Imprensa",
+ "transparencyReport": "Relatório de Transparência",
+ "foundation": "Fundação",
+ "appSupport": "Suporte de {appName}",
+ "socials": "Redes Sociais",
+ "aria": {
+ "socialLink": "Ligação para {appName} no {platform}",
+ "rssLink": "Ligação para o feed RSS"
+ }
+ },
+ "languageSelection": {
+ "title": "Selecione o seu idioma",
+ "description": "Selecione o seu idioma preferido na lista abaixo",
+ "aria": {
+ "currentLanguage": "{language} (idioma atual)",
+ "switchToLanguage": "Mudar para {language}",
+ "currentLanguageIndicator": "(atual)"
+ }
+ },
+ "notFound": {
+ "pageNotFound": "Esta página não parece existir.",
+ "description": "Parece que a ligação que trouxe até aqui está incorreta."
+ },
+ "email": {
+ "heading": "Todas as atualizações de projeto, diretamente na sua caixa de entrada.",
+ "subheading": "Receba um e-mail cerca de uma vez por mês.",
+ "placeholder": "O seu email",
+ "submitSuccessConfirm": "Obrigado! Verifique a sua caixa de entrada para confirmar a subscrição.",
+ "button": {
+ "text": "Inscrever-se"
+ },
+ "joinCommunity": "Junte-se à {appName} {featureCommunity} e conheça o grupo vibrante de pessoas que constroem, mantêm e utilizam o Session."
+ },
+ "landing": {
+ "hero": {
+ "heading": "Send Messages, Not Metadata.",
+ "tag": "Encontre a sua liberdade com o {appName}",
+ "glitchTextGlitch": "Encriptadas"
+ },
+ "about": {
+ "title": "O que é o {appName}?",
+ "content": "O {appName} é um mensageiro com encriptação end-to-end que protege os seus dados pessoais . Retome o controlo com uma aplicação de mensagens concebida, construída e operada por uma comunidade global de especialistas em privacidade ."
+ },
+ "benefits": {
+ "title": "Benefícios",
+ "1": {
+ "heading": "Sem Números de Telefone",
+ "content": "Protect your identity with {featureAccountIds}. No phone number or email required to sign up."
+ },
+ "2": {
+ "heading": "Sem Vazamentos de Dados",
+ "content": "O {appName} não coleta dados, então não há nada a vazar."
+ },
+ "3": {
+ "heading": "Caminhos Seguros",
+ "content": "Caminhos roteados com onion protegem suas conversas de hackers e bisbilhoteiros."
+ },
+ "4": {
+ "heading": "Código Aberto",
+ "content": "{appName} has nothing to hide. Anyone can view, audit, and contribute to its code. "
+ },
+ "5": {
+ "heading": "Pessoas no Controle",
+ "content": "Milhares de {featureNodes} operadas por uma comunidade global. O {appName} é feito pelas pessoas, para as pessoas."
+ },
+ "6": {
+ "heading": "Sem Rastreadores",
+ "content": "Seus dados nunca são coletados, nunca rastreados e nunca vendidos a terceiros."
+ }
+ },
+ "features": {
+ "title": "Funcionalidades",
+ "heading": "Desfrute das funcionalidades que você adora e da segurança que precisa.",
+ "1": {
+ "heading": "Fale livremente",
+ "content": "Apenas você e a pessoa com quem está falando podem ver suas mensagens. Desfrute a sensação de liberdade com criptografia de ponta a ponta e mensagens autodestrutivas."
+ },
+ "2": {
+ "heading": "Mantenha o controle",
+ "content": "Você tem controle total sobre suas mensagens do início ao fim. Seja gerenciando suas próprias chaves de criptografia ou escolhendo um tema personalizado — o Session coloca você no comando."
+ },
+ "3": {
+ "heading": "Acompanhe seu grupo",
+ "content": "Quer esteja conversando com amigos próximos ou organizando um grande evento, é simples com {featureGroup} e {featureCommunity} (100+ membros) seguros."
+ }
+ }
+ },
+ "redirect": {
+ "heading": "Redirecionando...",
+ "content": "Clique aqui para voltar à página anterior."
+ },
+ "blog": {
+ "readMore": "Ler Mais",
+ "morePosts": "Mais publicações"
+ },
+ "download": {
+ "heading": "Transfira o {appName} para",
+ "mobile": "Telemóvel",
+ "desktop": "Computador",
+ "verifySignatures": "Verificar Assinaturas: {platforms}",
+ "releaseNotes": "Notas de Lançamento: {platforms}"
+ },
+ "imageAlt": {
+ "hero": "interface de aplicativo de mensagens privadas criptografadas para telemóvel",
+ "appLaptop": "aplicativo de mensagens privadas criptografadas executando num MacBook Pro",
+ "appMobile": "aplicativo de mensagens privadas criptografadas executando num iPhone"
+ },
+ "metadata": {
+ "default": {
+ "titleLayout": "{title} - Mensageiro Privado {appName}",
+ "title": "{appName} | Envie Mensagens, Não Metadados. | Mensageiro Privado",
+ "description": "{appName} é um mensageiro privado que visa eliminar qualquer possibilidade de coleta de metadados, roteando todas as mensagens por uma rede onion."
+ },
+ "download": {
+ "title": "Transferir",
+ "description": "Transfira o {appName} Hoje | O {appName} é um mensageiro com criptografia de ponta a ponta que elimina a coleta de dados sensíveis em todos os sistemas operacionais."
+ },
+ "faq": {
+ "title": "FAQ (Perguntas Mais Frequentes)",
+ "description": "Find answers to some of the most frequently asked questions about {appName}."
+ },
+ "litepaper": {
+ "description": "O {appName} é um mensageiro descentralizado que oferece comunicações completamente privadas, seguras e anónimas.",
+ "title": "{appName} Litepaper: Send Messages, Not Metadata"
+ },
+ "whitepaper": {
+ "description": "O {appName} é um mensageiro descentralizado que oferece comunicações completamente privadas, seguras e anónimas.",
+ "title": "{appName} Whitepaper: End-To-End Encrypted Conversations with Minimal Metadata Leakage"
+ },
+ "community": {
+ "title": "{appName} {featureCommunity}",
+ "description": "Junte-se à {featureCommunity} do {appName} e conheça o grupo vibrante de pessoas que constroem, operam e utilizam o {appName}."
+ },
+ "blog": {
+ "title": "Blogue",
+ "description": "Veja os Blogues do {appName}. | O {appName} é um mensageiro com criptografia de ponta a ponta que elimina a coleta de metadados sensíveis."
+ }
+ }
+}
\ No newline at end of file
diff --git a/locales/ro.json b/locales/ro.json
new file mode 100644
index 0000000..7709f04
--- /dev/null
+++ b/locales/ro.json
@@ -0,0 +1,176 @@
+{
+ "feature": {
+ "accountIds": "ID-uri de cont",
+ "nodes": "noduri",
+ "group": "Grup",
+ "community": "Comunitate"
+ },
+ "general": {
+ "download": "Descarcă",
+ "whitepaper": "Document tehnic",
+ "litepaper": "Document ușor",
+ "messages": "Mesaje",
+ "metadata": "Metadate",
+ "privacyPolicy": "Politica de confidențialitate",
+ "termsOfService": "Termeni și condiții",
+ "other": "Altele"
+ },
+ "navigation": {
+ "blog": "Blog",
+ "resources": "Resurse",
+ "docs": "Documentație",
+ "network": "Rețea",
+ "help": "Ajutor",
+ "faq": "Întrebări frecvente",
+ "support": "Asistență",
+ "aria": {
+ "whitepaper": "Link către whitepaper-ul {appName}",
+ "litepaper": "Link către litepaper-ul {appName}",
+ "sessionToken": "Link către site-ul token al {appName}",
+ "support": "Link către suportul {appName} prin Zendesk",
+ "iconButtonOpen": "Deschide meniul de navigare",
+ "iconButtonClose": "Închide meniul de navigare",
+ "downloadButton": "Link pentru descărcarea aplicației {appName}"
+ }
+ },
+ "footer": {
+ "about": "Despre",
+ "mediaKit": "Kit media",
+ "transparencyReport": "Raport de transparență",
+ "foundation": "Fundație",
+ "appSupport": "Asistență {appName}",
+ "socials": "Rețele sociale",
+ "aria": {
+ "socialLink": "Link către {appName} pe {platform}",
+ "rssLink": "Link către fluxul RSS"
+ }
+ },
+ "languageSelection": {
+ "title": "Selectează limba ta",
+ "description": "Selectează limba preferată din lista de mai jos",
+ "aria": {
+ "currentLanguage": "{language} (limba curentă)",
+ "switchToLanguage": "Schimbă în {language}",
+ "currentLanguageIndicator": "(curentă)"
+ }
+ },
+ "notFound": {
+ "pageNotFound": "Această pagină nu pare să existe.",
+ "description": "Se pare că linkul către această pagină a fost defect."
+ },
+ "email": {
+ "heading": "Fiecare actualizare de proiect, livrată direct în inbox-ul tău.",
+ "subheading": "Primești un e-mail cam o dată pe lună.",
+ "placeholder": "Emailul tău",
+ "submitSuccessConfirm": "Mulțumim! Verifică inbox-ul pentru a confirma abonarea.",
+ "button": {
+ "text": "Înregistrează-te"
+ },
+ "joinCommunity": "Alătură-te {appName} {featureCommunity} și întâlnește grupul vibrant de oameni care creează, gestionează și folosesc Session."
+ },
+ "landing": {
+ "hero": {
+ "heading": "Send Messages, Not Metadata.",
+ "tag": "Găsește-ți libertatea cu {appName}",
+ "glitchTextGlitch": "Criptate"
+ },
+ "about": {
+ "title": "Ce este {appName}?",
+ "content": "{appName} este un mesager criptat end-to-end care îți protejează datele personale . Recâștigă controlul cu o aplicație de mesagerie concepută, construită și operată de o comunitate globală de experți în confidențialitate ."
+ },
+ "benefits": {
+ "title": "Beneficii",
+ "1": {
+ "heading": "Fără numere de telefon",
+ "content": "Protect your identity with {featureAccountIds}. No phone number or email required to sign up."
+ },
+ "2": {
+ "heading": "Fără breșe de date",
+ "content": "{appName} nu colectează date, așa că nu are nimic de scurs."
+ },
+ "3": {
+ "heading": "Căi sigure",
+ "content": "Căile rutate prin onion îți protejează conversațiile de hackeri și interceptori."
+ },
+ "4": {
+ "heading": "Open source",
+ "content": "{appName} has nothing to hide. Anyone can view, audit, and contribute to its code. "
+ },
+ "5": {
+ "heading": "Putere prin oameni",
+ "content": "Mii de {featureNodes} operate de o comunitate globală. {appName} este creat de oameni, pentru oameni."
+ },
+ "6": {
+ "heading": "Fără trackere",
+ "content": "Datele tale nu sunt colectate niciodată, nici urmărite, și nici vândute către terți."
+ }
+ },
+ "features": {
+ "title": "Funcționalități",
+ "heading": "Bucură-te de funcționalitățile pe care le iubești și de securitatea de care ai nevoie.",
+ "1": {
+ "heading": "Vorbește liber",
+ "content": "Doar tu și persoana cu care vorbești puteți vedea mesajele. Bucură-te de sentimentul de libertate cu criptare end-to-end și mesaje care dispar."
+ },
+ "2": {
+ "heading": "Fii în control",
+ "content": "Deții controlul asupra mesajelor tale de la început până la sfârșit. Fie că gestionezi propriile tale chei de criptare sau alegi o temă personalizată — Session te pune la conducere."
+ },
+ "3": {
+ "heading": "Ține pasul cu grupul tău",
+ "content": "Indiferent dacă stai de vorbă cu prieteni apropiați sau organizezi un eveniment important, este ușor cu discuțiile {featureGroup} și {featureCommunity} (peste 100 de membri) securizate."
+ }
+ }
+ },
+ "redirect": {
+ "heading": "Redirecționare...",
+ "content": "Fă clic pe aici pentru a te întoarce la pagina anterioară."
+ },
+ "blog": {
+ "readMore": "Informații suplimentare",
+ "morePosts": "Mai multe articole"
+ },
+ "download": {
+ "heading": "Descarcă {appName} pentru",
+ "mobile": "Mobil",
+ "desktop": "Desktop",
+ "verifySignatures": "Verifică semnăturile: {platforms}",
+ "releaseNotes": "Note de lansare: {platforms}"
+ },
+ "imageAlt": {
+ "hero": "interfață aplicație mobilă de mesagerie privată criptată",
+ "appLaptop": "aplicație de mesagerie privată criptată rulând pe un macbook pro",
+ "appMobile": "aplicație de mesagerie privată criptată rulând pe un iPhone"
+ },
+ "metadata": {
+ "default": {
+ "titleLayout": "{title} - Mesager Privat {appName}",
+ "title": "{appName} | Trimite mesaje, nu metadate. | Mesager Privat",
+ "description": "{appName} este un mesager privat care are scopul de a elimina orice posibilitate de colectare a metadatelor prin redirecționarea tuturor mesajelor printr-o rețea onion."
+ },
+ "download": {
+ "title": "Descarcă",
+ "description": "Descarcă {appName} astăzi | {appName} este un mesager criptat end-to-end care elimină colectarea datelor sensibile de pe toate sistemele de operare."
+ },
+ "faq": {
+ "title": "Întrebări frecvente",
+ "description": "Find answers to some of the most frequently asked questions about {appName}."
+ },
+ "litepaper": {
+ "description": "{appName} este un mesager descentralizat care permite comunicații complet private, sigure și anonime.",
+ "title": "{appName} Litepaper: Send Messages, Not Metadata"
+ },
+ "whitepaper": {
+ "description": "{appName} este un mesager descentralizat care permite comunicații complet private, sigure și anonime.",
+ "title": "{appName} Whitepaper: End-To-End Encrypted Conversations with Minimal Metadata Leakage"
+ },
+ "community": {
+ "title": "{appName} {featureCommunity}",
+ "description": "Alătură-te {featureCommunity} din {appName} și cunoaște grupul dinamic de oameni care dezvoltă, operează și folosesc {appName}."
+ },
+ "blog": {
+ "title": "Blog",
+ "description": "Vizualizează blogurile {appName}. | {appName} este un mesager criptat end-to-end care elimină colectarea metadatelor sensibile."
+ }
+ }
+}
\ No newline at end of file
diff --git a/locales/sv.json b/locales/sv.json
new file mode 100644
index 0000000..b8b750f
--- /dev/null
+++ b/locales/sv.json
@@ -0,0 +1,176 @@
+{
+ "feature": {
+ "accountIds": "Kontonummer",
+ "nodes": "noder",
+ "group": "Grupp",
+ "community": "Community"
+ },
+ "general": {
+ "download": "Hämta",
+ "whitepaper": "Whitepaper",
+ "litepaper": "Litepaper",
+ "messages": "Meddelanden",
+ "metadata": "Metadata",
+ "privacyPolicy": "Integritetspolicy",
+ "termsOfService": "Användarvillkor",
+ "other": "Övrigt"
+ },
+ "navigation": {
+ "blog": "Blogg",
+ "resources": "Resurser",
+ "docs": "Dokumentation",
+ "network": "Nätverk",
+ "help": "Hjälp",
+ "faq": "FAQ",
+ "support": "Support",
+ "aria": {
+ "whitepaper": "Länk till {appName} Whitepaper",
+ "litepaper": "Länk till {appName} Litepaper",
+ "sessionToken": "Länk till {appName} Token-webbplats",
+ "support": "Länk till {appName} Support via Zendesk",
+ "iconButtonOpen": "Öppna navigationsmenyn",
+ "iconButtonClose": "Stäng navigationsmenyn",
+ "downloadButton": "Länk till {appName}-nedladdning"
+ }
+ },
+ "footer": {
+ "about": "Om",
+ "mediaKit": "Mediasats",
+ "transparencyReport": "Transparensrapport",
+ "foundation": "Stiftelse",
+ "appSupport": "{appName} Support",
+ "socials": "Sociala medier",
+ "aria": {
+ "socialLink": "Länk till {appName} på {platform}",
+ "rssLink": "Länk till RSS-flöde"
+ }
+ },
+ "languageSelection": {
+ "title": "Välj ditt språk",
+ "description": "Välj ditt föredragna språk från listan nedan",
+ "aria": {
+ "currentLanguage": "{language} (nuvarande språk)",
+ "switchToLanguage": "Byt till {language}",
+ "currentLanguageIndicator": "(nuvarande)"
+ }
+ },
+ "notFound": {
+ "pageNotFound": "Den här sidan verkar inte finnas.",
+ "description": "Det verkar som att länken hit var felaktig."
+ },
+ "email": {
+ "heading": "Varje projektuppdatering, direkt till din inkorg.",
+ "subheading": "Förvänta dig ett mejl ungefär en gång i månaden.",
+ "placeholder": "Din e-post",
+ "submitSuccessConfirm": "Tack! Kolla din inkorg för att bekräfta din prenumeration.",
+ "button": {
+ "text": "Registrera dig"
+ },
+ "joinCommunity": "Gå med i {appName} {featureCommunity} och träffa den livliga gruppen människor som bygger, underhåller och använder Session."
+ },
+ "landing": {
+ "hero": {
+ "heading": "Send Messages, Not Metadata.",
+ "tag": "Hitta din frihet med {appName}",
+ "glitchTextGlitch": "Krypterat"
+ },
+ "about": {
+ "title": "Vad är {appName}?",
+ "content": "{appName} är en ände-till-ände krypterad meddelandeapp som skyddar din personliga data. Ta tillbaka kontrollen med en meddelandeapp designad, utvecklad och driven av en global community av integritets experter."
+ },
+ "benefits": {
+ "title": "Fördelar",
+ "1": {
+ "heading": "Inga telefonnummer",
+ "content": "Protect your identity with {featureAccountIds}. No phone number or email required to sign up."
+ },
+ "2": {
+ "heading": "Inga dataintrång",
+ "content": "{appName} samlar inte in data, så det finns inget att läcka."
+ },
+ "3": {
+ "heading": "Säkra vägar",
+ "content": "Lökroutade vägar skyddar dina konversationer från hackare och avlyssnare."
+ },
+ "4": {
+ "heading": "Öppen källkod",
+ "content": "{appName} has nothing to hide. Anyone can view, audit, and contribute to its code. "
+ },
+ "5": {
+ "heading": "Drivet av människor",
+ "content": "Tusentals {featureNodes} drivs av ett globalt community. {appName} är av folket, för folket."
+ },
+ "6": {
+ "heading": "Inga spårare",
+ "content": "Dina data samlas aldrig in, spåras aldrig och säljs aldrig till tredje part."
+ }
+ },
+ "features": {
+ "title": "Funktioner",
+ "heading": "Njut av funktionerna du älskar och säkerheten du behöver.",
+ "1": {
+ "heading": "Tala fritt",
+ "content": "Bara du och den du pratar med kan se dina meddelanden. Njut av känslan av frihet med end-to-end-kryptering och självförstörande meddelanden."
+ },
+ "2": {
+ "heading": "Behåll kontrollen",
+ "content": "Du har kontroll över dina meddelanden från början till slut. Oavsett om det handlar om att hantera dina egna krypteringsnycklar eller välja ett anpassat tema – Session ger dig kontrollen."
+ },
+ "3": {
+ "heading": "Häng med din grupp",
+ "content": "Oavsett om du uppdaterar dig med nära vänner eller organiserar ett stort event, är det enkelt med säkra {featureGroup}- och {featureCommunity}-chattar (100+ medlemmar)."
+ }
+ }
+ },
+ "redirect": {
+ "heading": "Omdirigerar...",
+ "content": "Klicka här för att återgå till föregående sida."
+ },
+ "blog": {
+ "readMore": "Läs mer",
+ "morePosts": "Fler inlägg"
+ },
+ "download": {
+ "heading": "Ladda ner {appName} för",
+ "mobile": "Mobil",
+ "desktop": "Dator",
+ "verifySignatures": "Verifiera signaturer: {platforms}",
+ "releaseNotes": "Versionsanteckningar: {platforms}"
+ },
+ "imageAlt": {
+ "hero": "mobil krypterad privat meddelandeapp gränssnittsvy",
+ "appLaptop": "krypterad privat meddelandeapp som körs på en MacBook Pro",
+ "appMobile": "krypterad privat meddelandeapp som körs på en iPhone"
+ },
+ "metadata": {
+ "default": {
+ "titleLayout": "{title} - {appName} Privat Messenger",
+ "title": "{appName} | Skicka meddelanden, inte metadata. | Privat Messenger",
+ "description": "{appName} är en privat messenger som syftar till att eliminera möjligheten till metadatainsamling genom att dirigera alla meddelanden via ett lökroutat nätverk."
+ },
+ "download": {
+ "title": "Hämta",
+ "description": "Ladda ner {appName} idag | {appName} är en end-to-end-krypterad messenger som eliminerar insamling av känsliga metadata för alla operativsystem."
+ },
+ "faq": {
+ "title": "Vanliga frågor",
+ "description": "Find answers to some of the most frequently asked questions about {appName}."
+ },
+ "litepaper": {
+ "description": "{appName} är en decentraliserad messenger som stöder fullständigt privata, säkra och anonyma kommunikationer.",
+ "title": "{appName} Litepaper: Send Messages, Not Metadata"
+ },
+ "whitepaper": {
+ "description": "{appName} är en decentraliserad messenger som stöder fullständigt privata, säkra och anonyma kommunikationer.",
+ "title": "{appName} Whitepaper: End-To-End Encrypted Conversations with Minimal Metadata Leakage"
+ },
+ "community": {
+ "title": "{appName} {featureCommunity}",
+ "description": "Gå med i {appName} {featureCommunity} och möt den livliga gruppen människor som bygger, driver och använder {appName}."
+ },
+ "blog": {
+ "title": "Blogg",
+ "description": "Visa {appName} bloggar. | {appName} är en end-to-end-krypterad messenger som eliminerar insamling av känsliga metadata."
+ }
+ }
+}
\ No newline at end of file
diff --git a/locales/zh-CN.json b/locales/zh-CN.json
new file mode 100644
index 0000000..4f9ad5a
--- /dev/null
+++ b/locales/zh-CN.json
@@ -0,0 +1,176 @@
+{
+ "feature": {
+ "accountIds": "账户 ID",
+ "nodes": "节点",
+ "group": "群组",
+ "community": "社群"
+ },
+ "general": {
+ "download": "下载",
+ "whitepaper": "白皮书",
+ "litepaper": "轻论文",
+ "messages": "消息",
+ "metadata": "元数据",
+ "privacyPolicy": "隐私政策",
+ "termsOfService": "服务条款",
+ "other": "其它"
+ },
+ "navigation": {
+ "blog": "博客",
+ "resources": "资源",
+ "docs": "文档",
+ "network": "网络",
+ "help": "帮助",
+ "faq": "常见问题",
+ "support": "支持",
+ "aria": {
+ "whitepaper": "链接至 {appName} 白皮书",
+ "litepaper": "链接至 {appName} 轻论文",
+ "sessionToken": "链接至 {appName} 代币网站",
+ "support": "通过 Zendesk 联系 {appName} 支持",
+ "iconButtonOpen": "打开导航菜单",
+ "iconButtonClose": "关闭导航菜单",
+ "downloadButton": "链接到 {appName} 下载页面"
+ }
+ },
+ "footer": {
+ "about": "关于",
+ "mediaKit": "媒体工具包",
+ "transparencyReport": "透明度报告",
+ "foundation": "基金会",
+ "appSupport": "{appName} 支持",
+ "socials": "社交平台",
+ "aria": {
+ "socialLink": "链接至 {platform} 上的 {appName}",
+ "rssLink": "链接至 RSS 订阅源"
+ }
+ },
+ "languageSelection": {
+ "title": "选择您的语言",
+ "description": "从下方列表中选择您偏好的语言",
+ "aria": {
+ "currentLanguage": "{language}(当前语言)",
+ "switchToLanguage": "切换至 {language}",
+ "currentLanguageIndicator": "(当前)"
+ }
+ },
+ "notFound": {
+ "pageNotFound": "此页面似乎不存在。",
+ "description": "看起来指向此处的链接有误。"
+ },
+ "email": {
+ "heading": "每个项目更新,直接送达您的收件箱。",
+ "subheading": "大约每月会收到一封邮件。",
+ "placeholder": "您的电子邮件",
+ "submitSuccessConfirm": "感谢订阅!请查收您的邮箱以确认订阅。",
+ "button": {
+ "text": "注册"
+ },
+ "joinCommunity": "加入{appName} {featureCommunity} ,与全球热情的构建者、运营者和使用者见面交流。"
+ },
+ "landing": {
+ "hero": {
+ "heading": "发送 消息, 不发送非元数据。",
+ "tag": "使用 {appName} 找回您的自由",
+ "glitchTextGlitch": "已加密"
+ },
+ "about": {
+ "title": "什么是 {appName}?",
+ "content": "{appName} 是一款采用端到端 加密的消息应用,保护您的个人 数据。由全球 隐私 专家社群共同设计、构建并维护,让您重新掌握控制权。"
+ },
+ "benefits": {
+ "title": "优势",
+ "1": {
+ "heading": "无手机号码",
+ "content": "使用 {featureAccountIds} 保护您的身份。 注册无需提供电话号码或邮箱。"
+ },
+ "2": {
+ "heading": "无数据泄露",
+ "content": "{appName} 不收集数据, 因此无可泄露之物。"
+ },
+ "3": {
+ "heading": "安全路径",
+ "content": "洋葱路由路径可防止黑客和窃听者 窃取您的对话内容。"
+ },
+ "4": {
+ "heading": "开源",
+ "content": "{appName} 毫无隐瞒。任何人都可以 查看、审核并为其代码做出贡献。 "
+ },
+ "5": {
+ "heading": "由用户驱动",
+ "content": "由全球社区运行的数千个 {featureNodes}。 {appName} 源于用户,服务用户。"
+ },
+ "6": {
+ "heading": "无追踪器",
+ "content": "您的数据永远不会被收集、追踪, 也不会出售给第三方。"
+ }
+ },
+ "features": {
+ "title": "功能",
+ "heading": "享受您喜爱的功能,同时保障所需的安全性。",
+ "1": {
+ "heading": "畅所欲言",
+ "content": "只有您和对方才能看到您的消息。端到端加密与阅后即焚消息功能,为您带来自由的沟通体验。"
+ },
+ "2": {
+ "heading": "掌控一切",
+ "content": "从头到尾,您掌控自己的消息。无论是管理加密密钥还是选择自定义主题—Session 都给予您主导权。"
+ },
+ "3": {
+ "heading": "紧随您的圈子",
+ "content": "无论是与好友叙旧,还是组织大型活动,通过安全的 {featureGroup} 和 {featureCommunity}(100+ 成员)聊天都轻而易举。"
+ }
+ }
+ },
+ "redirect": {
+ "heading": "正在跳转……",
+ "content": "点击 此处 返回上一页。"
+ },
+ "blog": {
+ "readMore": "了解更多",
+ "morePosts": "更多文章"
+ },
+ "download": {
+ "heading": "下载 {appName} 适用于",
+ "mobile": "手机",
+ "desktop": "桌面",
+ "verifySignatures": "验证签名:{platforms}",
+ "releaseNotes": "发行说明:{platforms}"
+ },
+ "imageAlt": {
+ "hero": "移动端加密的私人消息应用界面展示",
+ "appLaptop": "运行于 MacBook Pro 上的加密私人消息应用",
+ "appMobile": "运行于 iPhone 上的加密私人消息应用"
+ },
+ "metadata": {
+ "default": {
+ "titleLayout": "{title} - {appName} 私人消息应用",
+ "title": "{appName} | 发送消息,不发送元数据。| 私人消息应用",
+ "description": "{appName} 是一款私人消息应用,旨在通过将所有消息通过洋葱路由网络传输,彻底消除收集元数据的可能性。"
+ },
+ "download": {
+ "title": "下载",
+ "description": "立即下载 {appName} | {appName} 是一款端到端加密的消息应用,针对所有操作系统移除敏感元数据的收集。"
+ },
+ "faq": {
+ "title": "常见问题",
+ "description": "查找关于 {appName} 的一些常见问题。"
+ },
+ "litepaper": {
+ "description": "{appName} 是一款去中心化的消息应用,支持完全私密、安全和匿名的通信。",
+ "title": "{appName} 轻文档:发送消息,而非元数据"
+ },
+ "whitepaper": {
+ "description": "{appName} 是一款去中心化的消息应用,支持完全私密、安全和匿名的通信。",
+ "title": "{appName} 白皮书:端到端加密对话,最小化元数据泄露"
+ },
+ "community": {
+ "title": "{appName} {featureCommunity}",
+ "description": "加入 {appName} {featureCommunity},结识正在构建、运行和使用 {appName} 的充满活力的用户群体。"
+ },
+ "blog": {
+ "title": "博客",
+ "description": "查看 {appName} 博客。| {appName} 是一款端到端加密的消息应用,消除敏感元数据的收集。"
+ }
+ }
+}
\ No newline at end of file
diff --git a/locales/zh-TW.json b/locales/zh-TW.json
new file mode 100644
index 0000000..32fe8cd
--- /dev/null
+++ b/locales/zh-TW.json
@@ -0,0 +1,176 @@
+{
+ "feature": {
+ "accountIds": "帳號 ID",
+ "nodes": "節點",
+ "group": "群組",
+ "community": "社群"
+ },
+ "general": {
+ "download": "下載",
+ "whitepaper": "白皮書",
+ "litepaper": "簡明白皮書",
+ "messages": "訊息",
+ "metadata": "中繼資料",
+ "privacyPolicy": "隱私政策",
+ "termsOfService": "服務條款",
+ "other": "其他"
+ },
+ "navigation": {
+ "blog": "部落格",
+ "resources": "資源",
+ "docs": "文件",
+ "network": "網路",
+ "help": "幫助",
+ "faq": "常見問題",
+ "support": "支援",
+ "aria": {
+ "whitepaper": "前往 {appName} 白皮書的連結",
+ "litepaper": "前往 {appName} 簡明白皮書的連結",
+ "sessionToken": "前往 {appName} 代幣網站的連結",
+ "support": "透過 Zendesk 聯絡 {appName} 支援",
+ "iconButtonOpen": "開啟導覽選單",
+ "iconButtonClose": "關閉導覽選單",
+ "downloadButton": "前往 {appName} 下載的連結"
+ }
+ },
+ "footer": {
+ "about": "關於",
+ "mediaKit": "媒體工具包",
+ "transparencyReport": "透明度報告",
+ "foundation": "基金會",
+ "appSupport": "{appName} 支援",
+ "socials": "社群媒體",
+ "aria": {
+ "socialLink": "前往 {platform} 上的 {appName}",
+ "rssLink": "前往 RSS 訂閱"
+ }
+ },
+ "languageSelection": {
+ "title": "選擇您的語言",
+ "description": "從下方清單中選擇您偏好的語言",
+ "aria": {
+ "currentLanguage": "{language}(目前語言)",
+ "switchToLanguage": "切換為 {language}",
+ "currentLanguageIndicator": "(目前)"
+ }
+ },
+ "notFound": {
+ "pageNotFound": "此頁面似乎不存在。",
+ "description": "看起來這個連結有問題。"
+ },
+ "email": {
+ "heading": "每一則專案更新,都將直送您的信箱。",
+ "subheading": "大約每月收到一封電子郵件。",
+ "placeholder": "你的電子郵件",
+ "submitSuccessConfirm": "感謝你!請檢查收件匣以確認你的訂閱。",
+ "button": {
+ "text": "註冊"
+ },
+ "joinCommunity": "加入 {appName} {featureCommunity} ,與一群熱情的人們一起建立、營運並使用 Session。"
+ },
+ "landing": {
+ "hero": {
+ "heading": "Send Messages, Not Metadata.",
+ "tag": "使用 {appName} 找回你的自由",
+ "glitchTextGlitch": "已加密"
+ },
+ "about": {
+ "title": "{appName} 是什麼?",
+ "content": "{appName} 是一款 端對端 加密的即時通訊工具,可保護你的個人 資料。這是一款由全球 隱私 專家社群設計、開發及營運的通訊應用,讓你重新掌控權力。"
+ },
+ "benefits": {
+ "title": "優勢",
+ "1": {
+ "heading": "無需電話號碼",
+ "content": "Protect your identity with {featureAccountIds}. No phone number or email required to sign up."
+ },
+ "2": {
+ "heading": "無資料外洩",
+ "content": "{appName} 不收集資料, 所以不會有資料洩漏。"
+ },
+ "3": {
+ "heading": "安全路徑",
+ "content": "經洋蔥路由的傳輸途徑保護你的對話 免於駭客與竊聽者的干擾。"
+ },
+ "4": {
+ "heading": "開放原始碼",
+ "content": "{appName} has nothing to hide. Anyone can view, audit, and contribute to its code. "
+ },
+ "5": {
+ "heading": "由人驅動",
+ "content": "由全球社群運行的數千個 {featureNodes}。 {appName} 是由人民、為人民設計的。"
+ },
+ "6": {
+ "heading": "無追蹤器",
+ "content": "你的資料永不被收集、追蹤, 也永不販售給第三方。"
+ }
+ },
+ "features": {
+ "title": "功能",
+ "heading": "享受你喜愛的功能和必需的安全性。",
+ "1": {
+ "heading": "自在對話",
+ "content": "只有你和你的對話對象可以看見訊息。透過端對端加密及閱後即焚訊息,享受自由對話的感覺。"
+ },
+ "2": {
+ "heading": "自主掌控",
+ "content": "你從頭到尾都能掌控自己的訊息。不論是管理自己的加密金鑰,或是自訂主題,Session 都讓你作主。"
+ },
+ "3": {
+ "heading": "與夥伴保持聯繫",
+ "content": "無論是與親密好友聯絡感情,還是籌辦大型活動,透過安全的 {featureGroup} 和 {featureCommunity}(可容納 100+ 成員)聊天室都毫不費力。"
+ }
+ }
+ },
+ "redirect": {
+ "heading": "正在重新導向……",
+ "content": "點擊 這裡 返回上一頁。"
+ },
+ "blog": {
+ "readMore": "了解更多",
+ "morePosts": "更多文章"
+ },
+ "download": {
+ "heading": "下載 {appName} 適用於",
+ "mobile": "行動電話",
+ "desktop": "桌面",
+ "verifySignatures": "驗證簽章:{platforms}",
+ "releaseNotes": "版本更新內容:{platforms}"
+ },
+ "imageAlt": {
+ "hero": "行動加密私密通訊應用程式介面展示",
+ "appLaptop": "在 MacBook Pro 上執行的加密私密通訊應用程式",
+ "appMobile": "在 iPhone 上執行的加密私密通訊應用程式"
+ },
+ "metadata": {
+ "default": {
+ "titleLayout": "{title} - {appName} 私密通訊工具",
+ "title": "{appName}|傳送訊息,不傳送中繼資料。|私密通訊工具",
+ "description": "{appName} 是一款私密通訊工具,透過洋蔥路由網路傳送所有訊息,避免任何中繼資料的蒐集。"
+ },
+ "download": {
+ "title": "下載",
+ "description": "立即下載 {appName}|{appName} 是一款端對端加密的通訊工具,可在各種作業系統下避免敏感中繼資料的蒐集。"
+ },
+ "faq": {
+ "title": "常見問題",
+ "description": "Find answers to some of the most frequently asked questions about {appName}."
+ },
+ "litepaper": {
+ "description": "{appName} 是一款去中心化的通訊工具,支援完全私密、安全且匿名的通訊。",
+ "title": "{appName} Litepaper: Send Messages, Not Metadata"
+ },
+ "whitepaper": {
+ "description": "{appName} 是一款去中心化的通訊工具,支援完全私密、安全且匿名的通訊。",
+ "title": "{appName} Whitepaper: End-To-End Encrypted Conversations with Minimal Metadata Leakage"
+ },
+ "community": {
+ "title": "{appName} {featureCommunity}",
+ "description": "加入 {appName} {featureCommunity},與一群熱情的人們一起建立、營運並使用 {appName}。"
+ },
+ "blog": {
+ "title": "部落格",
+ "description": "查看 {appName} 部落格。|{appName} 是一款端對端加密的通訊工具,可去除敏感中繼資料的蒐集。"
+ }
+ }
+}
\ No newline at end of file
diff --git a/next.config.js b/next.config.js
index 3d5c90e..b24a7c5 100644
--- a/next.config.js
+++ b/next.config.js
@@ -3,10 +3,10 @@ const withSvgr = require('@newhighsco/next-plugin-svgr');
const ContentSecurityPolicy = `
default-src 'self';
script-src 'self' ${
- process.env.NODE_ENV == 'development'
- ? "'unsafe-eval' 'unsafe-inline' "
- : ''
- }*.ctfassets.net *.youtube.com *.twitter.com;
+ process.env.NODE_ENV == 'development'
+ ? "'unsafe-eval' 'unsafe-inline' "
+ : ''
+}*.ctfassets.net *.youtube.com *.twitter.com;
child-src 'self' *.ctfassets.net *.youtube.com player.vimeo.com *.twitter.com;
style-src 'self' 'unsafe-inline' *.googleapis.com;
img-src 'self' blob: data: *.ctfassets.net *.youtube.com *.twitter.com;
@@ -16,44 +16,6 @@ const ContentSecurityPolicy = `
worker-src 'self' blob:;
`;
-const securityHeaders = () => {
- const headers = [
- {
- key: 'X-DNS-Prefetch-Control',
- value: 'on',
- },
- {
- key: 'Strict-Transport-Security',
- value: 'max-age=63072000; includeSubDomains; preload',
- },
- {
- key: 'X-XSS-Protection',
- value: '1; mode=block',
- },
- {
- key: 'X-Frame-Options',
- value: 'SAMEORIGIN',
- },
- {
- key: 'Permissions-Policy',
- value: 'camera=(), microphone=(), geolocation=(), interest-cohort=()',
- },
- {
- key: 'X-Content-Type-Options',
- value: 'nosniff',
- },
- {
- key: 'Referrer-Policy',
- value: 'strict-origin-when-cross-origin',
- },
- {
- key: 'Content-Security-Policy',
- value: ContentSecurityPolicy.replace(/\n/g, ''),
- },
- ];
- return headers;
-};
-
const redirects = [
{
source: '/android',
@@ -78,22 +40,50 @@ const redirects = [
destination: 'https://fdroid.getsession.org/',
permanent: true,
},
- {
- source: '/whitepaper',
- destination: 'https://arxiv.org/pdf/2002.04609.pdf',
- permanent: true,
- },
];
+const isTranslateMode =process.env.NEXT_PUBLIC_TRANSLATION_MODE === 'true';
+
+// TODO: enable all available locales as we get them fully translated
+const locales = !isTranslateMode ? [
+ 'en', // English
+ 'zh-CN', // Chinese Simplified
+ // 'zh-TW', // Chinese Traditional
+ 'cs', // Czech
+ 'nl', // Dutch
+ 'fr', // French
+ 'de', // German
+ 'hi', // Hindi
+ // 'hu', // Hungarian
+ 'it', // Italian
+ 'ja', // Japanese
+ 'pl', // Polish
+ // 'pt', // Portuguese
+ // 'ro', // Romanian
+ 'es', // Spanish
+ // 'sv', // Swedish
+] : ['ach'];
+
// @ts-check
/** @type {import('next').NextConfig} */
const nextConfig = {
+ i18n: {
+ locales,
+ defaultLocale: isTranslateMode ? 'ach' : 'en',
+ localeDetection: false,
+ },
+ trailingSlash: false,
reactStrictMode: true,
compress: true,
generateEtags: true,
- trailingSlash: false,
productionBrowserSourceMaps: false,
+ // SEO Enhancement: Enable static optimization
+ experimental: {
+ optimizeCss: true,
+ scrollRestoration: true,
+ },
+
env: {
STAGING_SECRET: process.env.STAGING_SECRET,
CONTENTFUL_SPACE_ID: process.env.CONTENTFUL_SPACE_ID,
@@ -103,9 +93,9 @@ const nextConfig = {
CAMPAIGN_MONITOR_CLIENT_ID: process.env.CAMPAIGN_MONITOR_CLIENT_ID,
CAMPAIGN_MONITOR_API_KEY: process.env.CAMPAIGN_MONITOR_API_KEY,
CAMPAIGN_MONITOR_LIST_SESSION_ID:
- process.env.CAMPAIGN_MONITOR_LIST_SESSION_ID,
+ process.env.CAMPAIGN_MONITOR_LIST_SESSION_ID,
CAMPAIGN_MONITOR_LIST_MARKET_RESEARCH_ID:
- process.env.CAMPAIGN_MONITOR_LIST_MARKET_RESEARCH_ID,
+ process.env.CAMPAIGN_MONITOR_LIST_MARKET_RESEARCH_ID,
MAILERLITE_API_KEY: process.env.MAILERLITE_API_KEY,
MAILERLITE_GROUP_ID: process.env.MAILERLITE_GROUP_ID,
},
@@ -114,8 +104,51 @@ const nextConfig = {
return [
{
source: '/(.*)',
- headers: securityHeaders(),
+ headers: [
+ {
+ key: 'X-DNS-Prefetch-Control',
+ value: 'on',
+ },
+ {
+ key: 'Strict-Transport-Security',
+ value: 'max-age=63072000; includeSubDomains; preload',
+ },
+ {
+ key: 'X-XSS-Protection',
+ value: '1; mode=block',
+ },
+ {
+ key: 'X-Frame-Options',
+ value: 'SAMEORIGIN',
+ },
+ {
+ key: 'Permissions-Policy',
+ value: 'camera=(), microphone=(), geolocation=(), interest-cohort=()',
+ },
+ {
+ key: 'X-Content-Type-Options',
+ value: 'nosniff',
+ },
+ {
+ key: 'Referrer-Policy',
+ value: 'strict-origin-when-cross-origin',
+ },
+ {
+ key: 'Content-Security-Policy',
+ value: ContentSecurityPolicy.replace(/\n/g, ''),
+ },
+ {
+ key: 'X-Robots-Tag',
+ value: 'index,follow,max-snippet:-1,max-image-preview:large,max-video-preview:-1',
+ },
+ // better caching
+ {
+ key: 'Vary',
+ value: 'Accept-Encoding, Accept-Language',
+ },
+ ],
},
+ // Caching for static assets
{
source: '/assets/:path*',
headers: [
@@ -123,6 +156,11 @@ const nextConfig = {
key: 'Cache-Control',
value: 'public, max-age=31536000, immutable',
},
+ // Preload hints for critical assets
+ {
+ key: 'Link',
+ value: '; rel=preload; as=style',
+ },
],
},
{
@@ -141,6 +179,56 @@ const nextConfig = {
key: 'Cache-Control',
value: 'public, max-age=31536000, immutable',
},
+ {
+ key: 'Access-Control-Allow-Origin',
+ value: '*',
+ },
+ ],
+ },
+ {
+ source: '/((?!api|_next|assets|images|fonts).*)',
+ headers: [
+ {
+ key: 'Cache-Control',
+ value: 'public, max-age=3600, must-revalidate',
+ },
+ ],
+ },
+ {
+ source: '/api/:path*',
+ headers: [
+ {
+ key: 'Cache-Control',
+ value: 'public, max-age=300, s-maxage=600, stale-while-revalidate=86400',
+ },
+ ],
+ },
+ // Sitemap caching
+ {
+ source: '/sitemap.xml',
+ headers: [
+ {
+ key: 'Cache-Control',
+ value: 'public, max-age=3600, s-maxage=7200',
+ },
+ {
+ key: 'Content-Type',
+ value: 'application/xml',
+ },
+ ],
+ },
+ // RSS feed caching
+ {
+ source: '/feed/:path*',
+ headers: [
+ {
+ key: 'Cache-Control',
+ value: 'public, max-age=3600, s-maxage=7200',
+ },
+ {
+ key: 'Content-Type',
+ value: 'application/rss+xml',
+ },
],
},
];
@@ -157,8 +245,10 @@ const nextConfig = {
],
deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
- formats: ['image/webp'],
+ formats: ['image/avif', 'image/webp'], // AVIF first for better compression
minimumCacheTTL: 86400,
+ dangerouslyAllowSVG: false, // Security best practice
+ contentSecurityPolicy: "default-src 'self'; script-src 'none'; sandbox;",
},
async redirects() {
@@ -179,6 +269,14 @@ const nextConfig = {
source: '/sitemap.xml',
destination: '/api/sitemap',
},
+ {
+ source: '/sitemap-:page.xml',
+ destination: '/api/sitemap/:page',
+ },
+ {
+ source: '/robots.txt',
+ destination: '/api/robots',
+ },
{
source: '/linux',
destination: '/api/download/linux',
@@ -218,7 +316,7 @@ const nextConfig = {
];
},
- // Webpack optimizations for better bundle splitting
+ // SEO Enhancement: Improved Webpack optimizations
webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
// Optimize bundle size in production
if (!dev && !isServer) {
@@ -239,10 +337,14 @@ const nextConfig = {
},
},
};
+
+ // SEO Enhancement: Tree shaking and dead code elimination
+ config.optimization.usedExports = true;
+ config.optimization.sideEffects = false;
}
return config;
},
};
-module.exports = withSvgr(nextConfig);
+module.exports = withSvgr(nextConfig);
\ No newline at end of file
diff --git a/package.json b/package.json
index 0f08f6a..a8ac0e6 100644
--- a/package.json
+++ b/package.json
@@ -18,6 +18,7 @@
"@contentful/rich-text-html-renderer": "^15.3.5",
"@contentful/rich-text-plain-text-renderer": "^15.3.5",
"@contentful/rich-text-react-renderer": "^15.3.5",
+ "@radix-ui/react-dialog": "^1.1.14",
"base-64": "^1.0.0",
"classnames": "^2.3.1",
"contentful": "^8.4.2",
@@ -26,11 +27,14 @@
"direction": "^2.0.1",
"feed": "^4.2.2",
"himalaya": "^1.1.0",
+ "lucide-react": "^0.525.0",
"next": "15.4.2",
+ "next-intl": "^4.3.4",
"react": "19.1.0",
"react-dom": "19.1.0",
"react-qrcode-logo": "^3.0.0",
"react-use": "^17.2.4",
+ "rtl-detect": "^1.1.2",
"sharp": "^0.34.3",
"xss": "^1.0.9"
},
@@ -45,6 +49,7 @@
"@types/react": "19.1.8",
"@types/react-dom": "19.1.6",
"@types/rimraf": "^3.0.2",
+ "@types/rtl-detect": "^1.0.3",
"autoprefixer": "^10.2.5",
"contentful-cli": "^1.8.17",
"cssnano": "^4.1.11",
diff --git a/pages/404.tsx b/pages/404.tsx
index 8c33165..eb9f146 100644
--- a/pages/404.tsx
+++ b/pages/404.tsx
@@ -1,9 +1,12 @@
import classNames from 'classnames';
+import type { GetStaticProps, GetStaticPropsContext } from 'next';
+import { useTranslations } from 'next-intl';
import Container from '@/components/Container';
import Layout from '@/components/ui/Layout';
import METADATA from '@/constants/metadata';
export default function Custom404() {
+ const t = useTranslations('notFound');
return (
@@ -21,13 +24,19 @@ export default function Custom404() {
)}
>
- This page doesn't seem to exist.
+ {t('pageNotFound')}
- {METADATA[404].DESCRIPTION}
+ {t('description')}
);
}
+
+export const getStaticProps: GetStaticProps = async (context: GetStaticPropsContext) => {
+ return {
+ props: { messages: (await import(`../locales/${context.locale}.json`)).default },
+ };
+};
diff --git a/pages/[slug].tsx b/pages/[slug].tsx
index 83dc91f..703afd4 100644
--- a/pages/[slug].tsx
+++ b/pages/[slug].tsx
@@ -10,6 +10,7 @@ import { type IPage, type IPost, isPost } from '@/types/cms';
interface Props {
content: IPage | IPost;
otherPosts?: IPost[];
+ messages?: any;
}
export default function Page(props: Props): ReactElement {
@@ -40,7 +41,9 @@ export async function getStaticProps(context: GetStaticPropsContext) {
// embedded links in content body need metadata for preview
content.body = await generateLinkMeta(content.body);
- const props: Props = { content };
+
+ const messages = (await import(`../locales/${context.locale}.json`)).default;
+ const props: Props = { content, messages };
if (isPost(content)) {
// we want 6 posts excluding the current one if it's found
diff --git a/pages/_app.tsx b/pages/_app.tsx
index 68e9e7a..8fa3ca1 100644
--- a/pages/_app.tsx
+++ b/pages/_app.tsx
@@ -1,6 +1,8 @@
import '@/styles/globals.css';
import type { AppProps } from 'next/app';
+import { useRouter } from 'next/router';
+import { NextIntlClientProvider } from 'next-intl';
import { ScreenProvider } from '@/contexts/screen';
if (process.env.NODE_ENV === 'development' && typeof window !== 'undefined') {
@@ -11,10 +13,14 @@ if (process.env.NODE_ENV === 'development' && typeof window !== 'undefined') {
}
function MyApp({ Component, pageProps }: AppProps) {
+ const router = useRouter();
+
return (
-
-
-
+
+
+
+
+
);
}
diff --git a/pages/_document.tsx b/pages/_document.tsx
index da5e7b0..20cac81 100644
--- a/pages/_document.tsx
+++ b/pages/_document.tsx
@@ -1,4 +1,5 @@
import Document, { type DocumentContext, Head, Html, Main, NextScript } from 'next/document';
+import { getLangDir } from 'rtl-detect';
class MyDocument extends Document {
static async getInitialProps(ctx: DocumentContext) {
@@ -7,8 +8,11 @@ class MyDocument extends Document {
}
render() {
+ const locale = this.props.locale || 'en';
+ const direction = getLangDir(locale);
+
return (
-
+
diff --git a/pages/api/sitemap.ts b/pages/api/sitemap.ts
index 100ce65..b3b83f6 100644
--- a/pages/api/sitemap.ts
+++ b/pages/api/sitemap.ts
@@ -1,11 +1,70 @@
import { readdirSync } from 'node:fs';
import type { NextApiRequest, NextApiResponse } from 'next';
-import getConfig from 'next/config';
+import config from 'next.config';
import { METADATA } from '@/constants';
import { fetchBlogEntries, fetchPages } from '@/services/cms';
import type { IRedirection } from '@/services/redirect';
import type { IPost } from '@/types/cms';
+const LOCALIZED_PAGES = ['', 'download', 'blog', 'community'];
+
+const redirects: IRedirection[] = await config.redirects();
+const locales: Array = config.i18n.locales;
+const defaultLocale: string = config.i18n.defaultLocale;
+
+enum ChangeFrequency {
+ // Constantly changing and include index pages on major news publications, Google News, stock market data and social bookmarking categories.
+ Always = 'Always',
+ // Update every hour and will also include major news publications as well as weather services and forums.
+ Hourly = 'Hourly',
+ // Updated on average once per day and include things like blog posts, smaller web forum pages, message boards and classified ads.
+ Daily = 'Daily',
+ // Updates typically occur once per week, these pages will include website directories, product info and pricing pages as well as less frequent blogs.
+ Weekly = 'Weekly',
+ // Updated roughly once per month and include category pages, FAQs, Help Desk articles that require occasional updates.
+ Monthly = 'Monthly',
+ // Updates on these pages happen on an annual basis and are typically your contact page, “About” page, login pages and registration pages.
+ Yearly = 'Yearly',
+ // Never ever get updates. These are really old blog posts, press releases, notifications about updates that never need updating and any completely static pages.
+ Never = 'Never',
+}
+
+const changeFrequencies = Object.values(ChangeFrequency);
+
+function isChangeFrequency(frequency: unknown): frequency is ChangeFrequency {
+ return typeof frequency === 'string' && changeFrequencies.includes(frequency as ChangeFrequency);
+}
+
+interface LocalizedUrl {
+ url: string;
+ alternates: Array<{ locale: string; url: string }>;
+ lastmod?: string;
+ published?: string;
+ priority?: number;
+ changeFrequency?: ChangeFrequency;
+}
+
+function handlePriority(priority: number) {
+ if (typeof priority !== 'number' || priority > 1 || priority < 0) {
+ throw new Error('Priority must be a number between 0 and 1');
+ }
+ return priority;
+}
+
+const overridePageOptions: Record> = {
+ '': { priority: 1.0, changeFrequency: ChangeFrequency.Weekly },
+ download: { priority: 0.9, changeFrequency: ChangeFrequency.Weekly },
+ blog: { priority: 0.9, changeFrequency: ChangeFrequency.Weekly },
+ faq: { priority: 0.9, changeFrequency: ChangeFrequency.Weekly },
+ litepaper: { priority: 0.75, changeFrequency: ChangeFrequency.Yearly },
+ whitepaper: { priority: 0.75, changeFrequency: ChangeFrequency.Yearly },
+};
+
+function getOverridePageOptions(slug: string) {
+ const page = overridePageOptions[slug];
+ return page ?? {};
+}
+
export default async function handler(_req: NextApiRequest, res: NextApiResponse) {
const baseUrl = {
development: 'http://localhost:3000',
@@ -13,7 +72,48 @@ export default async function handler(_req: NextApiRequest, res: NextApiResponse
production: METADATA.HOST_URL,
}[process.env.NODE_ENV];
- const staticPages = readdirSync('pages')
+ const shouldLocalize = (slug: string): boolean => {
+ return LOCALIZED_PAGES.includes(slug);
+ };
+
+ const generateLocalizedUrls = (
+ slug: string,
+ lastmod?: string,
+ published?: string
+ ): LocalizedUrl[] => {
+ const overrides = getOverridePageOptions(slug);
+ if (!shouldLocalize(slug)) {
+ return [
+ {
+ url: `${baseUrl}/${slug}`,
+ alternates: [{ locale: defaultLocale, url: `${baseUrl}/${slug}` }],
+ lastmod,
+ published,
+ ...overrides,
+ },
+ ];
+ }
+
+ return locales.map((locale) => {
+ const isDefault = locale === defaultLocale;
+ const mainUrl = isDefault ? `${baseUrl}/${slug}` : `${baseUrl}/${locale}/${slug}`;
+
+ const alternates = locales.map((altLocale) => ({
+ locale: altLocale,
+ url: altLocale === defaultLocale ? `${baseUrl}/${slug}` : `${baseUrl}/${altLocale}/${slug}`,
+ }));
+
+ return {
+ url: mainUrl,
+ alternates,
+ lastmod,
+ published,
+ ...overrides,
+ };
+ });
+ };
+
+ const staticPageSlugs = readdirSync('pages')
.filter((page) => {
return ![
'.DS_Store',
@@ -30,25 +130,28 @@ export default async function handler(_req: NextApiRequest, res: NextApiResponse
})
.map((pagePath) => {
if (pagePath.includes('index')) {
- pagePath = '';
+ return '';
} else {
- pagePath = pagePath.split('.tsx')[0];
+ return pagePath.split('.tsx')[0];
}
- return `${baseUrl}/${pagePath}`;
});
- const redirectPages = getConfig().serverRuntimeConfig.redirects.map((redirect: IRedirection) => {
- if (redirect.source.includes(':slug')) {
- return '';
- } else {
- return `${baseUrl}${redirect.source}`;
- }
- });
+ const staticPages = staticPageSlugs.flatMap((slug) =>
+ generateLocalizedUrls(slug, new Date().toISOString())
+ );
+
+ const redirectPageSlugs = redirects
+ .filter((redirect: IRedirection) => !redirect.source.includes(':slug'))
+ .map((redirect: IRedirection) => redirect.source.replace(/^\//, '')); // Remove leading slash
+
+ const redirectPages = redirectPageSlugs.flatMap((slug) =>
+ generateLocalizedUrls(slug, new Date().toISOString())
+ );
const { entries: _dynamicPages } = await fetchPages();
- const dynamicPages = _dynamicPages.map((page) => {
- return `${baseUrl}/${page.slug}`;
- });
+ const dynamicPages = _dynamicPages.flatMap((page) =>
+ generateLocalizedUrls(page.slug, new Date().toISOString())
+ );
const _blogPages: IPost[] = [];
let currentPage = 1;
@@ -67,39 +170,46 @@ export default async function handler(_req: NextApiRequest, res: NextApiResponse
currentPage++;
}
- const blogPages = _blogPages.map((page) => {
- return {
- url: `${baseUrl}/blog/${page.slug}`,
- published: page.publishedDateISO,
- };
- });
+ const blogPages: LocalizedUrl[] = _blogPages.map((page) => ({
+ url: `${baseUrl}/blog/${page.slug}`,
+ alternates: [{ locale: defaultLocale, url: `${baseUrl}/blog/${page.slug}` }],
+ lastmod: page.publishedDateISO,
+ published: page.publishedDateISO,
+ }));
+
+ const allPages = [...staticPages, ...redirectPages, ...dynamicPages, ...blogPages];
const sitemap = `
-
- ${[...staticPages, ...redirectPages, ...dynamicPages]
- .map((url) => {
+
+ ${allPages
+ .map((page) => {
+ const isLocalized = page.alternates.length > 1;
+
+ let hreflangLinks = '';
+ if (isLocalized) {
+ hreflangLinks = [
+ // Add x-default pointing to default locale version
+ ` `,
+ // Add all locale-specific alternates
+ ...page.alternates.map(
+ (alt) =>
+ ` `
+ ),
+ ].join('\n');
+ }
+
return `
- ${url}
- ${new Date().toISOString()}
- monthly
- 1.0
+ ${page.url}
+ ${page.published || page.lastmod}
+ ${isChangeFrequency(page.changeFrequency) ? page.changeFrequency : ChangeFrequency.Monthly}
+ ${page.priority !== undefined ? handlePriority(page.priority) : 0.5}
+${hreflangLinks}
`;
})
.join('')}
- ${blogPages
- .map((post) => {
- return `
-
- ${post.url}
- ${post.published}
- monthly
- 1.0
-
- `;
- })
- .join('')}
`;
diff --git a/pages/blog/index.tsx b/pages/blog/index.tsx
index 3e623a0..5d260a2 100644
--- a/pages/blog/index.tsx
+++ b/pages/blog/index.tsx
@@ -33,7 +33,7 @@ export const getStaticProps: GetStaticProps = async (_context: GetStaticPropsCon
}
return {
- props: { posts },
+ props: { posts, messages: (await import(`../../locales/${_context.locale}.json`)).default },
revalidate: CMS.CONTENT_REVALIDATE_RATE,
};
};
@@ -42,7 +42,7 @@ export default function Blog(props: Props): ReactElement {
const { posts } = props;
const [featuredPost, ...otherPosts] = posts;
return (
-
+
+
);
}
+
+export const getStaticProps: GetStaticProps = async (context: GetStaticPropsContext) => {
+ return {
+ props: { messages: (await import(`../locales/${context.locale}.json`)).default },
+ };
+};
diff --git a/pages/download.tsx b/pages/download.tsx
index 09d11e7..0fb9480 100644
--- a/pages/download.tsx
+++ b/pages/download.tsx
@@ -1,8 +1,10 @@
/* eslint-disable @next/next/no-html-link-for-pages */
import classNames from 'classnames';
+import type { GetStaticProps, GetStaticPropsContext } from 'next';
import Image from 'next/legacy/image';
import Link from 'next/link';
+import { useLocale, useTranslations } from 'next-intl';
import type { ReactElement } from 'react';
import { ReactComponent as AndroidSVG } from '@/assets/svgs/android_robot_head.svg';
import { ReactComponent as AppleSVG } from '@/assets/svgs/apple.svg';
@@ -11,9 +13,14 @@ import { ReactComponent as LinuxSVG } from '@/assets/svgs/linux.svg';
import { ReactComponent as WindowsSVG } from '@/assets/svgs/windows.svg';
import Container from '@/components/Container';
import Layout from '@/components/ui/Layout';
+import { NON_LOCALIZED_STRING } from '@/constants/localization';
import METADATA from '@/constants/metadata';
export default function Download(): ReactElement {
+ const locale = useLocale();
+ const t = useTranslations('download');
+ const tImage = useTranslations('imageAlt');
+
const panelClasses = classNames('mx-auto text-center', 'lg:w-1/2 lg:flex lg:flex-col lg:pb-16');
const headingClasses = 'text-5xl font-semibold';
const subtitleClasses = classNames('text-2xl', 'lg:text-3xl');
@@ -43,7 +50,7 @@ export default function Download(): ReactElement {
'transition-colors duration-300'
);
return (
-
+