mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-07-16 17:46:18 +08:00
feat: add i18n
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
import i18next from 'i18next';
|
||||
import { initReactI18next } from 'react-i18next';
|
||||
import en_US from './resources/en.json';
|
||||
import zh_CN from './resources/zh.json';
|
||||
|
||||
const resources = {
|
||||
en: en_US,
|
||||
zh: zh_CN,
|
||||
} as const;
|
||||
|
||||
i18next.use(initReactI18next).init({
|
||||
lng: 'en',
|
||||
fallbackLng: 'en',
|
||||
resources,
|
||||
interpolation: {
|
||||
escapeValue: false, // not needed for react as it escapes by default
|
||||
},
|
||||
});
|
||||
|
||||
export const options = [
|
||||
{ value: 'en', text: 'English' },
|
||||
{ value: 'zh', text: '简体中文' },
|
||||
];
|
||||
|
||||
export { i18next };
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"translation": {
|
||||
"Open Source": "Open Source",
|
||||
"Privacy First": "Privacy First",
|
||||
"Alternative": "Alternative",
|
||||
"Check GitHub": "Check GitHub",
|
||||
"Try it Online": "Try it Online",
|
||||
"description1": {
|
||||
"part1": "Affine is the next-generation collaborative knowledge base for professionals.",
|
||||
"part2": "It's not just a collection of Docs, whiteboard, and tables.",
|
||||
"part3": "Transform any building block as you like.",
|
||||
"part4": "Say goodbye to redundancy. Store your data once, and keep your data as you like it."
|
||||
},
|
||||
"description2": {
|
||||
"part1": "Shape Your Page",
|
||||
"part2": "Docs, Kanbans, and Databases are all fully functional anywhere, anytime. A truly what-you-see-is-what-you-get environment for your data.",
|
||||
"part3": "All pages come with a document (Paper Mode) and whiteboard (Edgeless Mode) view."
|
||||
},
|
||||
"description3": {
|
||||
"part1": "Plan Your Task",
|
||||
"part2": "No more chaos managing multiple views.",
|
||||
"part3": "Set a TODO with Markdown, and seamlessly edit it within a Kanban.",
|
||||
"part4": "Managing multi-dimensional tables should be this simple - and now it is."
|
||||
},
|
||||
"description4": {
|
||||
"part1": "Privacy-first, and collaborative. No compromises whatsoever.",
|
||||
"part2": "We don't like being locked-in, and neither should you. Privacy is at the foundation of everything we do, but it should not limit us that's why there are no compromises.",
|
||||
"part3": "Your data is yours;it is always locally stored and secured - available to you always. While still being able to enjoy collaboration features such as real-time editing and sharing with others, without any cloud setup."
|
||||
},
|
||||
"BuildFor": "Build for an open and semantic future",
|
||||
"KeepUpdated": "Keep Updated on",
|
||||
"Join": "Join Our Community"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"translation": {
|
||||
"Open Source": "开源",
|
||||
"Privacy First": "隐私第一",
|
||||
"Alternative": "的另一种选择",
|
||||
"Check GitHub": "GitHub中查看",
|
||||
"Try it Online": "在线上试试",
|
||||
"description1": {
|
||||
"part1": "Affine是面向专业人士的下一代协同知识库",
|
||||
"part2": "它不仅仅是一个文档、白板和表格的集合。",
|
||||
"part3": "可以根据需要转换任何构建块。",
|
||||
"part4": "向冗余说再见吧。将数据存储一次,并保留您喜欢的数据。"
|
||||
},
|
||||
"description2": {
|
||||
"part1": "塑造您的页面",
|
||||
"part2": "文档、看板和数据库在任何地方、任何时候都是完全可用的,一个真正的“所见即所得”的数据环境。",
|
||||
"part3": "所有页面都有一个文档(纸张模式)和白板(无边缘模式)视图。"
|
||||
},
|
||||
"description3": {
|
||||
"part1": "计划您的任务",
|
||||
"part2": "不再混乱地管理多个视图。",
|
||||
"part3": "使用 Markdown 设置 TODO,并在看板中无缝地编辑它。",
|
||||
"part4": "管理多维表格本应该就这么简单——现在的它就是这么简单。"
|
||||
},
|
||||
"description4": {
|
||||
"part1": "隐私第一,合作无间,绝不妥协。",
|
||||
"part2": "我们不喜欢被关起来,您也不应该。隐私是我们做任何事情的基础,但它不应该限制我们,这就是为什么我们决不妥协。",
|
||||
"part3": "您的数据是您自己的,它总是安全的在本地存储并随时供您使用。您不需要任何云设置就可以享受协作功能,即时编辑和与他人共享。"
|
||||
},
|
||||
"BuildFor": "构建一个开放和语义化的未来",
|
||||
"KeepUpdated": "持续更新在",
|
||||
"Join": "加入我们的社区"
|
||||
}
|
||||
}
|
||||
@@ -7,12 +7,15 @@ import GitHubIcon from '@mui/icons-material/GitHub';
|
||||
import RedditIcon from '@mui/icons-material/Reddit';
|
||||
import TelegramIcon from '@mui/icons-material/Telegram';
|
||||
import { Box, Button, Container, Grid, SvgIcon, Typography } from '@mui/joy';
|
||||
import Option from '@mui/joy/Option';
|
||||
import Select from '@mui/joy/Select';
|
||||
import { CssVarsProvider, styled } from '@mui/joy/styles';
|
||||
import { LogoIcon } from '@toeverything/components/icons';
|
||||
// eslint-disable-next-line no-restricted-imports
|
||||
import { useMediaQuery } from '@mui/material';
|
||||
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import CollaborationImage from './collaboration.png';
|
||||
import { options } from './i18n';
|
||||
import LogoImage from './logo.png';
|
||||
import PageImage from './page.png';
|
||||
import ShapeImage from './shape.png';
|
||||
@@ -199,6 +202,7 @@ const AffineImage = styled('img')({
|
||||
|
||||
const GitHub = (props: { center?: boolean; flat?: boolean }) => {
|
||||
const matches = useMediaQuery('(max-width: 1024px)');
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Button
|
||||
@@ -234,14 +238,14 @@ const GitHub = (props: { center?: boolean; flat?: boolean }) => {
|
||||
startIcon={<GitHubIcon />}
|
||||
size="lg"
|
||||
>
|
||||
{props.center ? 'Check ' : ''}GitHub
|
||||
{t(`${props.center ? 'Check ' : ''}GitHub`)}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
const AFFiNEOnline = (props: { center?: boolean; flat?: boolean }) => {
|
||||
const matches = useMediaQuery('(max-width: 1024px)');
|
||||
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Button
|
||||
onClick={() => {
|
||||
@@ -277,14 +281,18 @@ const AFFiNEOnline = (props: { center?: boolean; flat?: boolean }) => {
|
||||
startIcon={<LogoIcon />}
|
||||
size="lg"
|
||||
>
|
||||
Try it Online
|
||||
{t('Try it Online')}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
export function App() {
|
||||
const matches = useMediaQuery('(max-width: 1024px)');
|
||||
const { t, i18n } = useTranslation();
|
||||
|
||||
const changeLanguage = (event: any) => {
|
||||
i18n.changeLanguage(event);
|
||||
};
|
||||
return (
|
||||
<CssVarsProvider>
|
||||
<VenusContainer
|
||||
@@ -342,6 +350,13 @@ export function App() {
|
||||
>
|
||||
Blog
|
||||
</Button>
|
||||
<Select defaultValue="en" onChange={changeLanguage}>
|
||||
{options.map(option => (
|
||||
<Option key={option.value} value={option.value}>
|
||||
{option.text}
|
||||
</Option>
|
||||
))}
|
||||
</Select>
|
||||
</Grid>
|
||||
</Grid>
|
||||
<Grid
|
||||
@@ -369,7 +384,7 @@ export function App() {
|
||||
},
|
||||
}}
|
||||
>
|
||||
Open Source,
|
||||
{t('Open Source')},
|
||||
</Typography>
|
||||
<Typography
|
||||
fontSize="96px"
|
||||
@@ -380,7 +395,7 @@ export function App() {
|
||||
},
|
||||
}}
|
||||
>
|
||||
Privacy First
|
||||
{t('Privacy First')}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Grid>
|
||||
@@ -413,7 +428,7 @@ export function App() {
|
||||
},
|
||||
}}
|
||||
>
|
||||
Alternative
|
||||
{t('Alternative')}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Grid>
|
||||
@@ -432,8 +447,7 @@ export function App() {
|
||||
fontWeight={'400'}
|
||||
sx={{ color: '#888' }}
|
||||
>
|
||||
Affine is the next-generation collaborative
|
||||
knowledge base for professionals.
|
||||
{t('description1.part1')}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Grid>
|
||||
@@ -488,8 +502,7 @@ export function App() {
|
||||
level={matches ? 'h2' : 'h1'}
|
||||
fontWeight={'bold'}
|
||||
>
|
||||
It’s not just a collection of Docs, whiteboard, and
|
||||
tables.
|
||||
{t('description1.part2')}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Grid>
|
||||
@@ -506,11 +519,10 @@ export function App() {
|
||||
}}
|
||||
>
|
||||
<Typography fontSize="1.2em">
|
||||
Transform any building block as you like.
|
||||
{t('description1.part3')}
|
||||
</Typography>
|
||||
<Typography fontSize="1.2em">
|
||||
Say goodbye to redundancy. Store your data once, and
|
||||
keep your data as you like it.
|
||||
{t('description1.part4')}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Grid>
|
||||
@@ -547,23 +559,19 @@ export function App() {
|
||||
fontWeight={'bold'}
|
||||
style={{ marginBottom: '0.5em' }}
|
||||
>
|
||||
Shape Your Page
|
||||
{t('description2.part1')}
|
||||
</Typography>
|
||||
<Typography
|
||||
fontSize="1.2em"
|
||||
style={{ marginBottom: '0.25em' }}
|
||||
>
|
||||
Docs, Kanbans, and Databases are all fully
|
||||
functional anywhere, anytime. A truly
|
||||
what-you-see-is-what-you-get environment for
|
||||
your data.
|
||||
{t('description2.part2')}
|
||||
</Typography>
|
||||
<Typography
|
||||
fontSize="1.2em"
|
||||
style={{ marginBottom: '0.25em' }}
|
||||
>
|
||||
All pages come with a document (Paper Mode) and
|
||||
whiteboard (Edgeless Mode) view.
|
||||
{t('description2.part3')}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Grid>
|
||||
@@ -625,27 +633,25 @@ export function App() {
|
||||
fontWeight={'bold'}
|
||||
style={{ marginBottom: '0.5em' }}
|
||||
>
|
||||
Plan Your Task
|
||||
{t('description3.part1')}
|
||||
</Typography>
|
||||
<Typography
|
||||
fontSize="1.2em"
|
||||
style={{ marginBottom: '0.25em' }}
|
||||
>
|
||||
No more chaos managing multiple views.
|
||||
{t('description3.part2')}
|
||||
</Typography>
|
||||
<Typography
|
||||
fontSize="1.2em"
|
||||
style={{ marginBottom: '0.25em' }}
|
||||
>
|
||||
Set a TODO with Markdown, and seamlessly edit it
|
||||
within a Kanban.
|
||||
{t('description3.part3')}
|
||||
</Typography>
|
||||
<Typography
|
||||
fontSize="1.2em"
|
||||
style={{ marginBottom: '0.25em' }}
|
||||
>
|
||||
Managing multi-dimensional tables should be this
|
||||
simple – and now it is.
|
||||
{t('description3.part4')}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Grid>
|
||||
@@ -697,17 +703,13 @@ export function App() {
|
||||
fontWeight={'bold'}
|
||||
style={{ marginBottom: '0.5em' }}
|
||||
>
|
||||
Privacy-first, and collaborative. No compromises
|
||||
whatsoever.
|
||||
{t('description4.part1')}
|
||||
</Typography>
|
||||
<Typography
|
||||
fontSize="1.2em"
|
||||
style={{ marginBottom: '0.25em' }}
|
||||
>
|
||||
We don’t like being locked-in, and neither should
|
||||
you. Privacy is at the foundation of everything we
|
||||
do, but it should not limit us that’s+ why there are
|
||||
no compromises.
|
||||
{t('description4.part2')}
|
||||
</Typography>
|
||||
<Typography
|
||||
fontSize="1.2em"
|
||||
@@ -715,9 +717,9 @@ export function App() {
|
||||
>
|
||||
Your data is yours; it is always locally stored and
|
||||
secured - available to you always. While still being
|
||||
able to enjoy collaboration features such as
|
||||
real-time editing and sharing with others, without
|
||||
any cloud setup.
|
||||
able enjoy collaboration features such as real-time
|
||||
editing and sharing with others, without any cloud
|
||||
setup.
|
||||
</Typography>
|
||||
</Box>
|
||||
</Grid>
|
||||
@@ -762,7 +764,7 @@ export function App() {
|
||||
}}
|
||||
>
|
||||
<Typography fontSize={'1.5em'}>
|
||||
Build for an open and semantic future
|
||||
{t('BuildFor')}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Grid>
|
||||
@@ -778,7 +780,7 @@ export function App() {
|
||||
>
|
||||
<Typography level="h3" sx={{ display: 'flex' }}>
|
||||
<span style={{ alignSelf: 'center' }}>
|
||||
Keep Updated on
|
||||
{t('KeepUpdated')}
|
||||
</span>
|
||||
<GitHub />
|
||||
</Typography>
|
||||
@@ -795,7 +797,7 @@ export function App() {
|
||||
}}
|
||||
>
|
||||
<Typography level="h2" sx={{ display: 'flex' }}>
|
||||
Join Our Community
|
||||
{t('Join')}
|
||||
</Typography>
|
||||
</Box>
|
||||
</Grid>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { StrictMode } from 'react';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import { BrowserRouter } from 'react-router-dom';
|
||||
import './app/i18n';
|
||||
|
||||
import App from './app';
|
||||
|
||||
|
||||
Reference in New Issue
Block a user