diff --git a/README.md b/README.md
index 59c9993d..7ea3cf05 100644
--- a/README.md
+++ b/README.md
@@ -27,11 +27,21 @@ Join our community chats to stay updated and collaborate:
Contributing is not just encouraged; it's easy!
+### Suggestions and new ideas
+
If you've solved a challenging problem or found a better way to explain a complex topic, share it:
— Got an idea? [Open an Issue](https://github.com/tact-lang/tact-docs/issues/new/choose).
— Ready to contribute? [Set up your Development Environment](#set-up-your-development-environment).
+## Translations
+
+At the moment, only Chinese translations are accepted.
+
+To add a new page, copy the existing one in English and add a `.zh` postfix after its name. For example, if the page is called `types.mdx`, copy it into the `types.zh.mdx` . Then, add the relevant info into the `_meta.zh.js` file (navigation on the left), which should be in the same folder as the modified page.
+
+Note, that you should **not** modify the folder structure or copy-paste folders.
+
## Set Up Your Development Environment
Before you submit your amazing contributions, ensure they work seamlessly.
diff --git a/configs-i18n/i18n-next.config.js b/configs-i18n/i18n-next.config.js
new file mode 100644
index 00000000..4eec57e2
--- /dev/null
+++ b/configs-i18n/i18n-next.config.js
@@ -0,0 +1,78 @@
+import { getHighlighter, BUNDLED_LANGUAGES } from 'shiki';
+import nextra from 'nextra';
+import fs from 'fs';
+
+const grammar_tact = JSON.parse(fs.readFileSync('./grammars/grammar-tact.json', 'utf-8'));
+const grammar_func = JSON.parse(fs.readFileSync('./grammars/grammar-func.json', 'utf-8'));
+const grammar_ohm = JSON.parse(fs.readFileSync('./grammars/grammar-ohm.json', 'utf-8'));
+
+const rehypePrettyCodeOptions = {
+ getHighlighter: options => {
+ return getHighlighter({
+ ...options,
+ langs: [
+ ...BUNDLED_LANGUAGES,
+ {
+ id: 'tact',
+ scopeName: 'source.tact',
+ grammar: grammar_tact,
+ aliases: ['tact'],
+ },
+ {
+ id: 'func',
+ scopeName: 'source.func',
+ grammar: grammar_func,
+ aliases: ['func'],
+ },
+ {
+ id: 'ohm',
+ scopeName: 'source.ohm',
+ grammar: grammar_ohm,
+ aliases: ['ohm'],
+ },
+ ],
+ });
+ },
+};
+
+/**
+ * @type {import('next').NextConfig}
+ */
+const withNextra = nextra({
+ theme: 'nextra-theme-docs',
+ themeConfig: './theme.config.jsx',
+ mdxOptions: {
+ rehypePrettyCodeOptions
+ },
+ latex: true,
+ defaultShowCopyCode: true
+});
+
+/**
+ * @type {import('next').NextConfig}
+ */
+export default withNextra({
+ output: 'export',
+ images: {
+ unoptimized: true
+ },
+ i18n: {
+ locales: ['default', 'en', 'zh'],
+ defaultLocale: 'default',
+ // localeDetection: false,
+ },
+ webpack(config) {
+ const allowedSvgRegex = /components\/icons\/.+\.svg$/
+
+ const fileLoaderRule = config.module.rules.find(rule =>
+ rule.test?.test?.('.svg')
+ )
+ fileLoaderRule.exclude = allowedSvgRegex
+
+ config.module.rules.push({
+ test: allowedSvgRegex,
+ use: ['@svgr/webpack']
+ })
+ return config
+ },
+});
diff --git a/configs-i18n/i18n-theme.config.jsx b/configs-i18n/i18n-theme.config.jsx
new file mode 100644
index 00000000..e14c8cef
--- /dev/null
+++ b/configs-i18n/i18n-theme.config.jsx
@@ -0,0 +1,98 @@
+import { useRouter } from 'next/router'
+import { DocsThemeConfig } from 'nextra-theme-docs'
+
+/**
+ * @type {DocsThemeConfig}
+ */
+const config = {
+ logo: (
+
+ ),
+ darkMode: true,
+ nextThemes: {
+ defaultTheme: 'dark',
+ },
+ project: {
+ link: 'https://github.com/tact-lang/tact-docs',
+ },
+ docsRepositoryBase: 'https://github.com/tact-lang/tact-docs/edit/main/',
+ i18n: [
+ { locale: 'en', text: 'English' },
+ { locale: 'zh', text: '中文' },
+ ],
+ sidebar: {
+ autoCollapse: true,
+ defaultMenuCollapseLevel: 1,
+ toggleButton: true,
+ },
+ feedback: {
+ content: null
+ },
+ // editLink: {
+ // text: function useText() {
+ // const { locale } = useRouter()
+ // return {
+ // 'en': 'Edit this page on GitHub',
+ // // 'zh': '在 GitHub 上编辑此页',
+ // }[locale ?? "en"]
+ // }
+ // },
+ footer: {
+ text:
+ CC BY 4.0, Tact Software Foundation
+ ,
+ },
+ toc: {
+ backToTop: true,
+ },
+ useNextSeoProps() {
+ return {
+ titleTemplate: '%s – Tact'
+ }
+ },
+ head: () => (
+ <>
+
+
+
+
+
+
+
+
+
+ ;
+ >
+ )
+}
+
+export default config
diff --git a/configs-i18n/next.config.js b/configs-i18n/next.config.js
new file mode 100644
index 00000000..7c2b813e
--- /dev/null
+++ b/configs-i18n/next.config.js
@@ -0,0 +1,73 @@
+import { getHighlighter, BUNDLED_LANGUAGES } from 'shiki';
+import nextra from 'nextra';
+import fs from 'fs';
+
+const grammar_tact = JSON.parse(fs.readFileSync('./grammars/grammar-tact.json', 'utf-8'));
+const grammar_func = JSON.parse(fs.readFileSync('./grammars/grammar-func.json', 'utf-8'));
+const grammar_ohm = JSON.parse(fs.readFileSync('./grammars/grammar-ohm.json', 'utf-8'));
+
+const rehypePrettyCodeOptions = {
+ getHighlighter: options => {
+ return getHighlighter({
+ ...options,
+ langs: [
+ ...BUNDLED_LANGUAGES,
+ {
+ id: 'tact',
+ scopeName: 'source.tact',
+ grammar: grammar_tact,
+ aliases: ['tact'],
+ },
+ {
+ id: 'func',
+ scopeName: 'source.func',
+ grammar: grammar_func,
+ aliases: ['func'],
+ },
+ {
+ id: 'ohm',
+ scopeName: 'source.ohm',
+ grammar: grammar_ohm,
+ aliases: ['ohm'],
+ },
+ ],
+ });
+ },
+};
+
+/**
+ * @type {import('next').NextConfig}
+ */
+const withNextra = nextra({
+ theme: 'nextra-theme-docs',
+ themeConfig: './theme.config.jsx',
+ mdxOptions: {
+ rehypePrettyCodeOptions
+ },
+ latex: true,
+ defaultShowCopyCode: true
+});
+
+/**
+ * @type {import('next').NextConfig}
+ */
+export default withNextra({
+ output: 'export',
+ images: {
+ unoptimized: true
+ },
+ webpack(config) {
+ const allowedSvgRegex = /components\/icons\/.+\.svg$/
+
+ const fileLoaderRule = config.module.rules.find(rule =>
+ rule.test?.test?.('.svg')
+ )
+ fileLoaderRule.exclude = allowedSvgRegex
+
+ config.module.rules.push({
+ test: allowedSvgRegex,
+ use: ['@svgr/webpack']
+ })
+ return config
+ },
+});
diff --git a/configs-i18n/theme.config.jsx b/configs-i18n/theme.config.jsx
new file mode 100644
index 00000000..4d037937
--- /dev/null
+++ b/configs-i18n/theme.config.jsx
@@ -0,0 +1,85 @@
+import { useRouter } from 'next/router'
+import { DocsThemeConfig } from 'nextra-theme-docs'
+
+/**
+ * @type {DocsThemeConfig}
+ */
+const config = {
+ logo: (
+
+ ),
+ darkMode: true,
+ nextThemes: {
+ defaultTheme: 'dark',
+ },
+ project: {
+ link: 'https://github.com/tact-lang/tact-docs',
+ },
+ docsRepositoryBase: 'https://github.com/tact-lang/tact-docs/edit/main/',
+ sidebar: {
+ autoCollapse: true,
+ defaultMenuCollapseLevel: 1,
+ toggleButton: true,
+ },
+ feedback: {
+ content: null
+ },
+ footer: {
+ text:
+ CC BY 4.0, Tact Software Foundation
+ ,
+ },
+ toc: {
+ backToTop: true,
+ },
+ useNextSeoProps() {
+ return {
+ titleTemplate: '%s – Tact'
+ }
+ },
+ head: () => (
+ <>
+
+
+
+
+
+
+
+
+
+ ;
+ >
+ )
+}
+
+export default config
diff --git a/next.config.js b/next.config.js
index 8f2612c7..cf082fe6 100644
--- a/next.config.js
+++ b/next.config.js
@@ -1,3 +1,8 @@
+/**
+* WARNING: This is an auto-generated file! Please, don't edit it directly.
+*
+* Instead, go to configs-i18n/ directory and modify files there.
+*/
import { getHighlighter, BUNDLED_LANGUAGES } from 'shiki';
import nextra from 'nextra';
import fs from 'fs';
@@ -56,12 +61,11 @@ export default withNextra({
images: {
unoptimized: true
},
- // i18n: {
- // // locales: ['default', 'en', 'zh'],
- // locales: ['default', 'en'],
- // defaultLocale: 'default',
- // // localeDetection: false,
- // },
+ i18n: {
+ locales: ['default', 'en', 'zh'],
+ defaultLocale: 'default',
+ // localeDetection: false,
+ },
webpack(config) {
const allowedSvgRegex = /components\/icons\/.+\.svg$/
@@ -76,4 +80,4 @@ export default withNextra({
})
return config
},
-});
\ No newline at end of file
+});
diff --git a/package.json b/package.json
index 69e89225..85e6ad1b 100644
--- a/package.json
+++ b/package.json
@@ -9,13 +9,19 @@
"react-dom": "^18.2.0"
},
"scripts": {
+ "next": "next",
"clean": "rm -fr .next out",
"deps": "yarn install --frozen-lockfile",
"dev": "yarn deps && yarn clean && next",
+ "check-links": "echo 'link checking'",
+ "check-spell": "echo 'spell checking'",
+ "check-format": "echo 'format checking'",
+ "check-all": "yarn check-links && yarn check-spell && yarn check-format",
+ "pre-build": "node ./scripts/pre-build.js",
"build": "yarn deps && yarn clean && next build",
- "post-build": "echo 'spell checking, link checking, formatting'",
- "build-pages": "yarn build && node ./scripts/redirects-generate.js",
- "next": "next"
+ "post-processing": "node ./scripts/redirects-generate.js",
+ "post-build": "node ./scripts/post-build.js && yarn check-all",
+ "build-pages": "yarn pre-build; yarn build && yarn post-processing; yarn post-build"
},
"devDependencies": {
"@svgr/webpack": "^8.1.0",
diff --git a/pages/_meta.zh.js b/pages/_meta.zh.js
new file mode 100644
index 00000000..330d4313
--- /dev/null
+++ b/pages/_meta.zh.js
@@ -0,0 +1,26 @@
+export default {
+ index: {
+ title: 'Tact Documentation',
+ type: 'page',
+ display: 'hidden',
+ theme: {
+ typesetting: 'article'
+ }
+ },
+ book: {
+ title: "Book",
+ type: 'page',
+ },
+ cookbook: {
+ title: "Cookbook",
+ type: 'page',
+ },
+ ref: {
+ title: "Reference",
+ type: 'page',
+ },
+ ecosystem: {
+ title: "Ecosystem",
+ type: 'page',
+ },
+}
diff --git a/scripts/post-build.js b/scripts/post-build.js
new file mode 100644
index 00000000..2cfeecac
--- /dev/null
+++ b/scripts/post-build.js
@@ -0,0 +1,24 @@
+// import fs from 'fs';
+// import path from 'path';
+import { overrideRootWithTargetConfig } from './pre-build.js';
+
+/* ---------------- */
+/* ---- Script ---- */
+/* ---------------- */
+
+// 1. Place correct configuration for the local i18n setup
+
+const configs = [
+ {
+ root: 'next.config.js',
+ target: 'i18n-next.config.js'
+ },
+ {
+ root: 'theme.config.jsx',
+ target: 'i18n-theme.config.jsx'
+ },
+];
+
+overrideRootWithTargetConfig(configs);
+
+// 2. TBD
diff --git a/scripts/pre-build.js b/scripts/pre-build.js
new file mode 100644
index 00000000..953b60fc
--- /dev/null
+++ b/scripts/pre-build.js
@@ -0,0 +1,78 @@
+import fs from 'fs';
+import path from 'path';
+
+/* ------------------- */
+/* ---- Functions ---- */
+/* ------------------- */
+
+/**
+ * Helper function to prevent unnecessary indentation
+ * @param str {string}
+ */
+function dedent(str) {
+ return ('' + str).replace(/(\n)\s+/g, '$1');
+}
+
+/**
+ * Overrides the root configs with target ones
+ *
+ * @param configs {{ root: string, target: string }[]}
+ */
+export const overrideRootWithTargetConfig = (configs) => {
+ // Current working directory of the process
+ const cwd = process.cwd();
+
+ // Not in the root dir of the repo
+ // if (!cwd.endsWith('tact-docs')) {
+ // console.log(`Error: not running from the root directory of the repo, but from ${cwd}`);
+ // process.exit(1);
+ // }
+
+ // Setup details for upcoming override
+ const pathPrefix = 'configs-i18n';
+
+ // Check that path exists
+ if (!fs.existsSync(path.join(cwd, pathPrefix))) {
+ console.log(`Error: ${pathPrefix} dir doesn't exist!`);
+ process.exit(1);
+ }
+
+ // Process all overrides
+ for (const conf of configs) {
+ const pathToRootConf = path.join(cwd, conf.root);
+ const pathToTargetConf = path.join(cwd, pathPrefix, conf.target);
+
+ const targetConfContents = fs.readFileSync(pathToTargetConf);
+
+ fs.writeFileSync(
+ pathToRootConf,
+ dedent(`/**
+ * WARNING: This is an auto-generated file! Please, don't edit it directly.
+ *
+ * Instead, go to ${pathPrefix}/ directory and modify files there.
+ */
+ `) + targetConfContents,
+ );
+ }
+}
+
+/* ---------------- */
+/* ---- Script ---- */
+/* ---------------- */
+
+// 1. Place correct configuration for the build
+
+const configs = [
+ {
+ root: 'next.config.js',
+ target: 'next.config.js'
+ },
+ {
+ root: 'theme.config.jsx',
+ target: 'theme.config.jsx'
+ },
+];
+
+overrideRootWithTargetConfig(configs);
+
+// 2. TBD
diff --git a/theme.config.jsx b/theme.config.jsx
index 93435121..f6546660 100644
--- a/theme.config.jsx
+++ b/theme.config.jsx
@@ -1,3 +1,8 @@
+/**
+* WARNING: This is an auto-generated file! Please, don't edit it directly.
+*
+* Instead, go to configs-i18n/ directory and modify files there.
+*/
import { useRouter } from 'next/router'
import { DocsThemeConfig } from 'nextra-theme-docs'
@@ -35,10 +40,10 @@ const config = {
link: 'https://github.com/tact-lang/tact-docs',
},
docsRepositoryBase: 'https://github.com/tact-lang/tact-docs/edit/main/',
- // i18n: [
- // { locale: 'en', text: 'English' },
- // // { locale: 'zh', text: '中文' },
- // ],
+ i18n: [
+ { locale: 'en', text: 'English' },
+ { locale: 'zh', text: '中文' },
+ ],
sidebar: {
autoCollapse: true,
defaultMenuCollapseLevel: 1,