diff --git a/apps/venus/src/app/common/Header.tsx b/apps/venus/src/app/common/Header.tsx
index 9a2e8d0173..2dc7c50ff0 100644
--- a/apps/venus/src/app/common/Header.tsx
+++ b/apps/venus/src/app/common/Header.tsx
@@ -13,7 +13,7 @@ import AFFiNETextLogo from './affine-text-logo.png';
import { HoverMenu } from './HoverMenu';
import { MobileHeader } from './MobileHeader';
-import { options } from '../i18n';
+import { LOCALES } from '../i18n';
export const AFFiNEHeader = () => {
const matches = useMediaQuery('(max-width: 1024px)');
@@ -140,15 +140,15 @@ export const AFFiNEHeader = () => {
}}
/>
diff --git a/apps/venus/src/app/i18n/index.ts b/apps/venus/src/app/i18n/index.ts
index 9ddaa8330d..f4428a9b09 100644
--- a/apps/venus/src/app/i18n/index.ts
+++ b/apps/venus/src/app/i18n/index.ts
@@ -1,25 +1,63 @@
-import i18next from 'i18next';
-import { initReactI18next } from 'react-i18next';
-import en_US from './resources/en.json';
-import zh_CN from './resources/zh.json';
+import i18next, { Resource } from 'i18next';
+import {
+ I18nextProvider,
+ initReactI18next,
+ useTranslation,
+} from 'react-i18next';
+import { LOCALES } from './resources';
+import type en_US from './resources/en.json';
-const resources = {
- en: en_US,
- zh: zh_CN,
-} as const;
+// See https://react.i18next.com/latest/typescript
+declare module 'react-i18next' {
+ interface CustomTypeOptions {
+ // custom namespace type if you changed it
+ // defaultNS: 'ns1';
+ // custom resources type
+ resources: {
+ en: typeof en_US;
+ };
+ }
+}
+
+const STORAGE_KEY = 'i18n_lng';
+
+export { i18n, useTranslation, I18nProvider, LOCALES };
+
+const resources = LOCALES.reduce(
+ (acc, { tag, res }) => ({ ...acc, [tag]: { translation: res } }),
+ {}
+);
+
+const fallbackLng = LOCALES[0].tag;
+const standardizeLocale = (language: string) => {
+ if (LOCALES.find(locale => locale.tag === language)) return language;
+ if (
+ LOCALES.find(
+ locale => locale.tag === language.slice(0, 2).toLowerCase()
+ )
+ )
+ return language;
+ return fallbackLng;
+};
+
+const language = standardizeLocale(
+ localStorage.getItem(STORAGE_KEY) ?? navigator.language
+);
+
+const i18n = i18next.createInstance();
+i18n.use(initReactI18next).init({
+ lng: language,
+ fallbackLng,
+ debug: process.env['NODE_ENV'] === 'development',
-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: '简体中文' },
-];
+i18n.on('languageChanged', lng => {
+ localStorage.setItem(STORAGE_KEY, lng);
+});
-export { i18next };
+const I18nProvider = I18nextProvider;
diff --git a/apps/venus/src/app/i18n/resources/en.json b/apps/venus/src/app/i18n/resources/en.json
index 80381df1d7..4dfc81af86 100644
--- a/apps/venus/src/app/i18n/resources/en.json
+++ b/apps/venus/src/app/i18n/resources/en.json
@@ -1,40 +1,39 @@
{
- "translation": {
- "Blog": "Blog",
- "AboutUs": "About Us",
- "Open Source": "Open Source",
- "Docs": "Docs",
- "Feedback": "Feedback",
- "ContactUs": "Contact Us",
- "Privacy First": "Privacy First",
- "Alternative": "Alternative",
- "Check GitHub": "Check GitHub",
- "Try it Online": "Try it Online",
- "language": "Language",
- "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"
- }
+ "Blog": "Blog",
+ "AboutUs": "About Us",
+ "Open Source": "Open Source",
+ "Docs": "Docs",
+ "Feedback": "Feedback",
+ "ContactUs": "Contact Us",
+ "Privacy First": "Privacy First",
+ "Alternative": "Alternative",
+ "Check GitHub": "Check GitHub",
+ "GitHub": "GitHub",
+ "Try it Online": "Try it Online",
+ "language": "Language",
+ "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"
}
diff --git a/apps/venus/src/app/i18n/resources/es.json b/apps/venus/src/app/i18n/resources/es.json
new file mode 100644
index 0000000000..034eb54f70
--- /dev/null
+++ b/apps/venus/src/app/i18n/resources/es.json
@@ -0,0 +1,32 @@
+{
+ "Alternative": "Alternativa",
+ "BuildFor": "Construir por un futuro abierto y semántico",
+ "Check GitHub": "Revisar en GitHub",
+ "Join": "Únete a nuestra comunidad",
+ "KeepUpdated": "Mantente actualizado",
+ "Open Source": "Código abierto",
+ "Privacy First": "La privacidad es lo primero",
+ "Try it Online": "Prueba Online",
+ "description1": {
+ "part1": "Affine es un base de conocimiento colaborativa de próxima generación para los profesionales.",
+ "part2": "Es más que una simple colección de Documentos, Pizarra y Tablas.",
+ "part3": "Transforma cualquier bloque como tu quieras. ",
+ "part4": "Dígale adios a la redundancia, Almacene sus datos una vez, y manténgalos como usted quiera."
+ },
+ "description2": {
+ "part1": "Dele forma a sus páginas.",
+ "part2": "Los Documentos, Kanbans y Base de datos son completamente funcionales en cualquier lugar, en cualquier momento. Un verdadero entorno de lo que ves y lo que obtienes para tus datos.",
+ "part3": "Todas las páginas tiene una vista de documento y de pizarra. "
+ },
+ "description3": {
+ "part1": "Programe sus tareas.",
+ "part2": "No más caos manejando múltiples vistas.",
+ "part3": "Establezca un TODO con Markdown, y edítelo sin problemas en un Kanban. ",
+ "part4": "La gestión de tablas multidimensionales debería ser así de fácil y ahora lo es."
+ },
+ "description4": {
+ "part1": "Privacidad en primer lugar, y colaboración sin compromiso. ",
+ "part2": "\nNo nos gusta estar encerrados, y a usted tampoco debería. La privacidad está en la base de todo lo que hacemos, pero no debe limitarnos, por eso no hay compromisos.",
+ "part3": "Sus datos son suyos; siempre están almacenados y protegidos de forma local, siempre disponibles para usted. Sin dejar de lado el poder disfrutar de funciones de colaboración como la edición en tiempo real y el uso compartido con otros, sin ninguna configuración en la nube."
+ }
+}
diff --git a/apps/venus/src/app/i18n/resources/index.ts b/apps/venus/src/app/i18n/resources/index.ts
new file mode 100644
index 0000000000..424560a398
--- /dev/null
+++ b/apps/venus/src/app/i18n/resources/index.ts
@@ -0,0 +1,24 @@
+import en from './en.json';
+import es from './es.json';
+import zh_Hans from './zh.json';
+
+export const LOCALES = [
+ {
+ name: 'English',
+ tag: 'en',
+ originalName: 'English',
+ res: en,
+ },
+ {
+ name: 'Simplified Chinese',
+ tag: 'zh-Hans',
+ originalName: '简体中文',
+ res: zh_Hans,
+ },
+ {
+ name: 'Spanish',
+ tag: 'es',
+ originalName: 'español',
+ res: es,
+ },
+] as const;
diff --git a/apps/venus/src/app/i18n/resources/zh.json b/apps/venus/src/app/i18n/resources/zh.json
index 545a644c28..e630e1c753 100644
--- a/apps/venus/src/app/i18n/resources/zh.json
+++ b/apps/venus/src/app/i18n/resources/zh.json
@@ -1,40 +1,38 @@
{
- "translation": {
- "Blog": "博客",
- "AboutUs": "关于我们",
- "Open Source": "开源",
- "Privacy First": "隐私第一",
- "Docs": "文档",
- "Feedback": "反馈",
- "ContactUs": "联系我们",
- "Alternative": "的另一种选择",
- "Check GitHub": "GitHub中查看",
- "Try it Online": "在线试用",
- "language": "语言",
- "description1": {
- "part1": "Affine是面向专业人士的下一代协同知识库",
- "part2": "它不仅仅是一个文档、白板和表格的集合。",
- "part3": "可以根据需要转换任何构建块。",
- "part4": "向冗余说再见吧。将数据存储一次,并保留您喜欢的数据。"
- },
- "description2": {
- "part1": "塑造您的页面",
- "part2": "文档、看板和数据库在任何地方、任何时候都是完全可用的,一个真正的“所见即所得”的数据环境。",
- "part3": "所有页面都有一个文档(纸张模式)和白板(无边缘模式)视图。"
- },
- "description3": {
- "part1": "计划您的任务",
- "part2": "不再混乱地管理多个视图。",
- "part3": "使用 Markdown 设置 TODO,并在看板中无缝地编辑它。",
- "part4": "管理多维表格本应该就这么简单——现在的它就是这么简单。"
- },
- "description4": {
- "part1": "隐私第一,合作无间,绝不妥协。",
- "part2": "我们不喜欢被关起来,您也不应该。隐私是我们做任何事情的基础,但它不应该限制我们,这就是为什么我们决不妥协。",
- "part3": "您的数据是您自己的,它总是安全的在本地存储并随时供您使用。您不需要任何云设置就可以享受协作功能,即时编辑和与他人共享。"
- },
- "BuildFor": "构建一个开放和语义化的未来",
- "KeepUpdated": "持续更新在",
- "Join": "加入我们的社区"
- }
+ "Blog": "博客",
+ "AboutUs": "关于我们",
+ "Open Source": "开源",
+ "Privacy First": "隐私第一",
+ "Docs": "文档",
+ "Feedback": "反馈",
+ "ContactUs": "联系我们",
+ "Alternative": "的另一种选择",
+ "Check GitHub": "GitHub中查看",
+ "Try it Online": "在线试用",
+ "language": "语言",
+ "description1": {
+ "part1": "Affine是面向专业人士的下一代协同知识库",
+ "part2": "它不仅仅是一个文档、白板和表格的集合。",
+ "part3": "可以根据需要转换任何构建块。",
+ "part4": "向冗余说再见吧。将数据存储一次,并保留您喜欢的数据。"
+ },
+ "description2": {
+ "part1": "塑造您的页面",
+ "part2": "文档、看板和数据库在任何地方、任何时候都是完全可用的,一个真正的“所见即所得”的数据环境。",
+ "part3": "所有页面都有一个文档(纸张模式)和白板(无边缘模式)视图。"
+ },
+ "description3": {
+ "part1": "计划您的任务",
+ "part2": "不再混乱地管理多个视图。",
+ "part3": "使用 Markdown 设置 TODO,并在看板中无缝地编辑它。",
+ "part4": "管理多维表格本应该就这么简单——现在的它就是这么简单。"
+ },
+ "description4": {
+ "part1": "隐私第一,合作无间,绝不妥协。",
+ "part2": "我们不喜欢被关起来,您也不应该。隐私是我们做任何事情的基础,但它不应该限制我们,这就是为什么我们决不妥协。",
+ "part3": "您的数据是您自己的,它总是安全的在本地存储并随时供您使用。您不需要任何云设置就可以享受协作功能,即时编辑和与他人共享。"
+ },
+ "BuildFor": "构建一个开放和语义化的未来",
+ "KeepUpdated": "持续更新在",
+ "Join": "加入我们的社区"
}