├── .env.example ├── .eslintrc.json ├── .gitignore ├── .npmrc ├── .vscode └── settings.json ├── README.md ├── README_ja.md ├── README_zh.md ├── actions └── newsletter.ts ├── app ├── BaiDuAnalytics.tsx ├── GoogleAdsense.tsx ├── GoogleAnalytics.tsx ├── PlausibleAnalytics.tsx ├── [locale] │ ├── about │ │ └── page.tsx │ ├── blog │ │ ├── BlogCard.tsx │ │ ├── [slug] │ │ │ └── page.tsx │ │ └── page.tsx │ ├── layout.tsx │ ├── page.tsx │ ├── privacy-policy │ │ └── page.tsx │ ├── terms-of-service │ │ └── page.tsx │ └── unsubscribe │ │ └── page.tsx ├── api │ └── newsletter │ │ └── route.ts ├── robots.ts └── sitemap.ts ├── blogs ├── en │ └── 1.demo.mdx ├── ja │ └── 1.demo.mdx └── zh │ ├── 1.demo.mdx │ └── 2.demo2.mdx ├── components.json ├── components ├── BuiltWithButton.tsx ├── LanguageDetectionAlert.tsx ├── LocaleSwitcher.tsx ├── TailwindIndicator.tsx ├── ThemeToggle.tsx ├── WebsiteLogo.tsx ├── footer │ ├── Badges.tsx │ ├── Footer.tsx │ └── Newsletter.tsx ├── header │ ├── Header.tsx │ ├── HeaderLinks.tsx │ └── MobileMenu.tsx ├── home │ └── index.tsx ├── icons │ ├── expanding-arrow.tsx │ ├── eye.tsx │ ├── index.tsx │ ├── loading-circle.tsx │ ├── loading-dots.module.css │ ├── loading-dots.tsx │ ├── loading-spinner.module.css │ ├── loading-spinner.tsx │ ├── moon.tsx │ └── sun.tsx ├── mdx │ ├── Aside.tsx │ ├── Callout.tsx │ ├── MDXComponents.tsx │ └── MdxCard.tsx ├── social-icons │ ├── icons.tsx │ └── index.tsx └── ui │ ├── alert.tsx │ ├── button.tsx │ ├── dropdown-menu.tsx │ ├── select.tsx │ ├── toast.tsx │ └── toaster.tsx ├── config └── site.ts ├── content ├── about │ ├── en.mdx │ ├── ja.mdx │ └── zh.mdx ├── privacy-policy │ ├── en.mdx │ ├── ja.mdx │ └── zh.mdx └── terms-of-service │ ├── en.mdx │ ├── ja.mdx │ └── zh.mdx ├── gtag.js ├── hooks └── use-toast.ts ├── i18n ├── messages │ ├── en.json │ ├── ja.json │ └── zh.json ├── request.ts └── routing.ts ├── lib ├── email.ts ├── getBlogs.ts ├── logger.ts ├── metadata.ts └── utils.ts ├── log └── .db69a462fcd0bc6ae6d0cc5220e6aa21ec198c81-audit.json ├── middleware.ts ├── next-env.d.ts ├── next.config.mjs ├── package.json ├── pnpm-lock.yaml ├── postcss.config.js ├── public ├── ads.txt ├── favicon.ico ├── logo.png ├── logo.svg ├── logo_nexty.png ├── og.png ├── og.webp ├── placeholder.svg ├── try-nexty.webp └── zs.jpeg ├── stores └── localeStore.ts ├── styles ├── globals.css └── loading.css ├── tailwind.config.ts ├── tsconfig.json └── types ├── blog.ts ├── common.ts └── siteConfig.ts /.env.example: -------------------------------------------------------------------------------- 1 | # ----------------------------------------------------------------------------- 2 | # Site info 3 | # ----------------------------------------------------------------------------- 4 | NEXT_PUBLIC_SITE_URL=http://localhost:3000 5 | NEXT_PUBLIC_LOCALE_DETECTION=false 6 | 7 | # ----------------------------------------------------------------------------- 8 | # Discord 9 | # ----------------------------------------------------------------------------- 10 | NEXT_PUBLIC_DISCORD_INVITE_URL="https://discord.com/invite/R7bUxWKRqZ" 11 | 12 | # ----------------------------------------------------------------------------- 13 | # Analytics 14 | # Google Analytics: https://analytics.google.com/analytics/web/ 15 | # Baidu Tongji: https://tongji.baidu.com/ 16 | # Plausible: https://plausible.io/ 17 | # ----------------------------------------------------------------------------- 18 | NEXT_PUBLIC_GOOGLE_ID= 19 | NEXT_PUBLIC_BAIDU_TONGJI= 20 | NEXT_PUBLIC_PLAUSIBLE_DOMAIN= 21 | NEXT_PUBLIC_PLAUSIBLE_SRC= 22 | 23 | #------------------------------------------------------------------------ 24 | # Ads 25 | # Google Adsense: https://www.google.com/adsense/ 26 | #------------------------------------------------------------------------ 27 | NEXT_PUBLIC_GOOGLE_ADSENSE_ID= 28 | 29 | #------------------------------------------------------------------------ 30 | # Resend: https://resend.com/ 31 | #------------------------------------------------------------------------ 32 | RESEND_API_KEY= 33 | ADMIN_EMAIL= 34 | RESEND_AUDIENCE_ID= 35 | 36 | #------------------------------------------------------------------------ 37 | # Upstash: https://upstash.com/ 38 | #------------------------------------------------------------------------ 39 | UPSTASH_REDIS_REST_URL= 40 | UPSTASH_REDIS_REST_TOKEN= 41 | UPSTASH_REDIS_NEWSLETTER_RATE_LIMIT_KEY=newsletter-rate-limit 42 | DAY_MAX_SUBMISSIONS= -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### Node template 2 | .idea 3 | .DS_Store 4 | dist 5 | 6 | # Logs 7 | logs 8 | *.log 9 | npm-debug.log* 10 | yarn-debug.log* 11 | yarn-error.log* 12 | lerna-debug.log* 13 | .temp 14 | yarn.lock 15 | 16 | # Diagnostic reports (https://nodejs.org/api/report.html) 17 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 18 | 19 | # Runtime data 20 | pids 21 | *.pid 22 | *.seed 23 | *.pid.lock 24 | 25 | # Directory for instrumented libs generated by jscoverage/JSCover 26 | lib-cov 27 | 28 | # Coverage directory used by tools like istanbul 29 | coverage 30 | *.lcov 31 | 32 | # nyc test coverage 33 | .nyc_output 34 | 35 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 36 | .grunt 37 | 38 | # Bower dependency directory (https://bower.io/) 39 | bower_components 40 | 41 | # node-waf configuration 42 | .lock-wscript 43 | 44 | # Compiled binary addons (https://nodejs.org/api/addons.html) 45 | build/Release 46 | 47 | # Dependency directories 48 | node_modules/ 49 | jspm_packages/ 50 | 51 | # Snowpack dependency directory (https://snowpack.dev/) 52 | web_modules/ 53 | 54 | # TypeScript cache 55 | *.tsbuildinfo 56 | 57 | # Optional npm cache directory 58 | .npm 59 | 60 | # Optional eslint cache 61 | .eslintcache 62 | 63 | # Microbundle cache 64 | .rpt2_cache/ 65 | .rts2_cache_cjs/ 66 | .rts2_cache_es/ 67 | .rts2_cache_umd/ 68 | 69 | # Optional REPL history 70 | .node_repl_history 71 | 72 | # Output of 'npm pack' 73 | *.tgz 74 | 75 | # Yarn Integrity file 76 | .yarn-integrity 77 | 78 | # dotenv environment variables file 79 | .env 80 | .env.local 81 | .env.test 82 | 83 | # parcel-bundler cache (https://parceljs.org/) 84 | .cache 85 | .parcel-cache 86 | 87 | # Next.js build output 88 | .next 89 | out 90 | 91 | # Nuxt.js build / generate output 92 | .nuxt 93 | dist 94 | 95 | # Gatsby files 96 | .cache/ 97 | # Comment in the assets line in if your project uses Gatsby and not Next.js 98 | # https://nextjs.org/blog/next-9-1#public-directory-support 99 | # assets 100 | 101 | # vuepress build output 102 | .vuepress/dist 103 | 104 | # Serverless directories 105 | .serverless/ 106 | 107 | # FuseBox cache 108 | .fusebox/ 109 | 110 | # DynamoDB Local files 111 | .dynamodb/ 112 | 113 | # TernJS port file 114 | .tern-port 115 | 116 | # Stores VSCode versions used for testing VSCode extensions 117 | .vscode-test 118 | 119 | # yarn v2 120 | .yarn/cache 121 | .yarn/unplugged 122 | .yarn/build-state.yml 123 | .yarn/install-state.gz 124 | .pnp.* 125 | 126 | /.vuepress/dist/ 127 | 128 | # sitemap 129 | */sitemap*.xml 130 | */robots.txt -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | # if use pnpm 2 | enable-pre-post-scripts=true 3 | public-hoist-pattern[]=*@nextui-org/* 4 | registry=https://registry.npmmirror.com/ 5 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "css.validate": false, 3 | "editor.formatOnSave": true, 4 | "editor.tabSize": 2, 5 | "editor.codeActionsOnSave": { 6 | "source.fixAll.eslint": "explicit", 7 | "source.organizeImports": "explicit" 8 | }, 9 | "headwind.runOnSave": false, 10 | "typescript.preferences.importModuleSpecifier": "non-relative", 11 | "eslint.validate": ["javascript", "javascriptreact", "typescript"], 12 | "typescript.tsdk": "node_modules/typescript/lib", 13 | "commentTranslate.source": "Bing", 14 | "cSpell.words": [ 15 | "contentlayer", 16 | "lemonsqueezy" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | --- 2 | Ship your SaaS faster with Nexty - the only Next.js boilerplate featuring a visual pricing dashboard, AI playground, and enterprise-level CMS, plus i18n, auth, payment, email, and SEO optimization. 3 | 4 | Try [Nexty.dev today](https://nexty.dev?utm_source=github-nextjs-starter) 5 | --- 6 | 7 | [](https://nexty.dev?utm_source=github-nextjs-starter) 8 | 9 | 10 | 🌍 *[English](README.md) ∙ [简体中文](README_zh.md) ∙ [日本語](README_ja.md)* 11 | 12 | # Next Forge - Multilingual Next.js 15 Starter 13 | 14 | A feature-rich Next.js 15 multilingual starter template to help you quickly build globally-ready websites. 15 | 16 | - [👉 Source Code](https://github.com/weijunext/nextjs-15-starter) 17 | - [👉 Live Demo](https://nextforge.dev/) 18 | 19 | **🚀 Looking for a full-featured SaaS Starter Template? [Check out the complete version](https://nexty.dev)** 20 | 21 | ## ✨ Features 22 | 23 | - 🌐 Built-in i18n support (English, Chinese, Japanese) 24 | - 🎨 Modern UI design with Tailwind CSS 25 | - 🌙 Dark/Light theme toggle 26 | - 📱 Responsive layout 27 | - 📝 MDX blog system 28 | - 🔍 SEO optimization 29 | - 📊 Integrated analytics tools 30 | - Google Analytics 31 | - Baidu Analytics 32 | - Google Adsense 33 | - Vercel Analytics 34 | 35 | ## 🚀 Quick Start 36 | 37 | ### Prerequisites 38 | 39 | - Node.js 18.17 or higher 40 | - pnpm 9.0 or higher (recommended) 41 | 42 | > **Note**: The project has configured `packageManager` field, we recommend using pnpm for the best experience. 43 | 44 | ### Installation 45 | 46 | 1. Clone the repository: 47 | ```bash 48 | git clone https://github.com/weijunext/nextjs-15-starter.git 49 | cd nextjs-15-starter 50 | ``` 51 | 52 | 2. Enable Corepack (recommended): 53 | ```bash 54 | corepack enable 55 | ``` 56 | 57 | 3. Install dependencies: 58 | ```bash 59 | pnpm install 60 | # or use other package managers 61 | npm install 62 | yarn 63 | ``` 64 | 65 | 4. Copy environment variables: 66 | ```bash 67 | cp .env.example .env 68 | ``` 69 | 70 | 5. Start the development server: 71 | ```bash 72 | pnpm dev 73 | # or npm run dev 74 | ``` 75 | 76 | Visit http://localhost:3000 to view your application. 77 | 78 | ## ⚙️ Configuration 79 | 80 | 1. Basic Setup 81 | - Edit `config/site.ts` for website information 82 | - Update icons and logo in `public/` 83 | - Configure `app/sitemap.ts` for sitemap 84 | - Update `app/robots.ts` for robots.txt 85 | 86 | 2. i18n Setup 87 | - Add/modify language files in `i18n/messages/` 88 | - Configure supported languages in `i18n/routing.ts` 89 | - Set up i18n routing in `middleware.ts` 90 | - Create pages under `app/[locale]/` 91 | - Use the `Link` component from `i18n/routing.ts` instead of Next.js default 92 | 93 | ## 📝 Content Management 94 | 95 | ### Blog Posts 96 | Create MDX files in `blog/[locale]` with the following format: 97 | 98 | ```markdown 99 | --- 100 | title: Post Title 101 | description: Post Description 102 | image: /image.png 103 | slug: /url-path 104 | tags: tag1,tag2 105 | date: 2025-02-20 106 | visible: published 107 | pin: true 108 | --- 109 | 110 | Post content... 111 | ``` 112 | 113 | Reference `types/blog.ts` for supported fields. 114 | 115 | ### Static Pages 116 | Manage static page content in `content/[page]/[locale].mdx`. 117 | 118 | ## 🔍 SEO Optimization 119 | 120 | Built-in comprehensive SEO features: 121 | - Server-side rendering and static generation 122 | - Automatic sitemap.xml generation 123 | - robots.txt configuration 124 | - Optimized metadata 125 | - Open Graph support 126 | - Multilingual SEO support 127 | 128 | ## 📊 Analytics 129 | 130 | Enable analytics by adding IDs in `.env`: 131 | ``` 132 | NEXT_PUBLIC_GOOGLE_ANALYTICS= 133 | NEXT_PUBLIC_BAIDU_TONGJI= 134 | NEXT_PUBLIC_GOOGLE_ADSENSE= 135 | ``` 136 | 137 | ## 📁 Project Structure 138 | 139 | ``` 140 | nextjs-15-starter/ 141 | ├── app/ # App directory 142 | │ ├── [locale]/ # Internationalized routes 143 | │ │ ├── about/ # About page 144 | │ │ ├── blog/ # Blog pages 145 | │ │ └── ... # Other pages 146 | │ ├── api/ # API routes 147 | │ └── globals/ # Global components 148 | ├── blog/ # Blog content (MDX) 149 | │ ├── en/ # English blog 150 | │ ├── ja/ # Japanese blog 151 | │ └── zh/ # Chinese blog 152 | ├── components/ # Reusable components 153 | │ ├── ui/ # Base UI components 154 | │ ├── header/ # Header components 155 | │ ├── footer/ # Footer components 156 | │ └── ... # Other components 157 | ├── config/ # Configuration files 158 | ├── content/ # Static content (MDX) 159 | ├── i18n/ # Internationalization 160 | │ ├── messages/ # Translation files 161 | │ ├── routing.ts # Routing configuration 162 | │ └── request.ts # Request configuration 163 | ├── lib/ # Utility functions 164 | ├── public/ # Static assets 165 | └── types/ # Type definitions 166 | ``` 167 | 168 | ## 🛠️ Tech Stack 169 | 170 | - **Framework**: Next.js 15 (App Router) 171 | - **Language**: TypeScript 172 | - **Styling**: Tailwind CSS + Shadcn/ui 173 | - **Internationalization**: next-intl 174 | - **Content**: MDX 175 | - **State Management**: Zustand 176 | - **Deployment**: Vercel 177 | - **Package Manager**: pnpm (recommended) 178 | 179 | ## 🚀 Deployment 180 | 181 | ### One-Click Deploy 182 | 183 | [![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/weijunext/nextjs-15-starter&project-name=&repository-name=nextjs-15-starter&demo-title=Nextjs15Starter&demo-description=Nextjs%2015%20starter.&demo-url=https://nextforge.dev&demo-image=https://nextforge.dev/og.png) 184 | 185 | ### Manual Deployment to Vercel 186 | 187 | 1. Push your code to GitHub 188 | 2. Import project in Vercel 189 | 3. Configure environment variables 190 | 4. Deploy 191 | 192 | ### Other Platforms 193 | 194 | ```bash 195 | # Build for production 196 | pnpm build 197 | 198 | # Start production server 199 | pnpm start 200 | ``` 201 | 202 | ## 💡 Development Best Practices 203 | 204 | ### Package Manager 205 | 206 | - Project configured with `packageManager: "pnpm@10.12.4"` 207 | - Enable Corepack: `corepack enable` 208 | - Team members should use the same pnpm version 209 | 210 | ### Code Quality 211 | 212 | ```bash 213 | # Lint code 214 | pnpm lint 215 | 216 | # Type checking 217 | pnpm type-check 218 | ``` 219 | 220 | ### Internationalization Development 221 | 222 | 1. Adding new language support: 223 | - Add new language files in `i18n/messages/` 224 | - Update `i18n/routing.ts` configuration 225 | - Create corresponding language directories in `blog/` and `content/` 226 | 227 | 2. Using translations: 228 | ```tsx 229 | import { useTranslations } from 'next-intl'; 230 | 231 | export default function MyComponent() { 232 | const t = useTranslations('namespace'); 233 | return

{t('title')}

; 234 | } 235 | ``` 236 | 237 | ## 🔧 Troubleshooting 238 | 239 | ### Common Issues 240 | 241 | **1. Package manager version mismatch** 242 | ```bash 243 | # Remove node_modules and lockfile 244 | rm -rf node_modules pnpm-lock.yaml 245 | # Reinstall 246 | pnpm install 247 | ``` 248 | 249 | **2. MDX files not displaying** 250 | - Check file path is correct 251 | - Verify frontmatter format 252 | - Ensure `visible` field is set to `published` 253 | 254 | **3. Internationalization routing issues** 255 | - Use `Link` component from `i18n/routing.ts` 256 | - Check `middleware.ts` configuration 257 | 258 | **4. Styles not working** 259 | - Verify Tailwind CSS class names are correct 260 | - Try restarting development server 261 | 262 | ### Environment Variables 263 | 264 | Ensure `.env` file contains necessary configuration: 265 | ```bash 266 | # Copy example config 267 | cp .env.example .env 268 | # Modify as needed 269 | ``` 270 | 271 | ## 📄 License 272 | 273 | MIT 274 | 275 | ## 🤝 Contributing 276 | 277 | Issues and Pull Requests are welcome! 278 | 279 | ## About the Author 280 | 281 | Next.js full-stack specialist providing expert services in project development, performance optimization, and SEO improvement. 282 | 283 | For consulting and training opportunities, reach out at weijunext@gmail.com 284 | 285 | - [Github](https://github.com/weijunext) 286 | - [Bento](https://bento.me/weijunext) 287 | - [Twitter/X](https://twitter.com/judewei_dev) 288 | 289 | Buy Me A Coffee 290 | 291 | [![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/G2G6TWWMG) -------------------------------------------------------------------------------- /README_ja.md: -------------------------------------------------------------------------------- 1 | --- 2 | Nexty で SaaS を迅速に立ち上げよう - ビジュアル料金ダッシュボード、AI プレイグラウンド、エンタープライズレベル CMS を備えた唯一の Next.js ボイラープレート。多言語対応、認証、決済、メール機能、SEO 最適化も完備。 3 | 4 | [Nexty.dev を今すぐ試す](https://nexty.dev?utm_source=github-nextjs-starter) 5 | --- 6 | 7 | [](https://nexty.dev?utm_source=github-nextjs-starter) 8 | 9 | 🌍 *[English](README.md) ∙ [简体中文](README_zh.md) ∙ [日本語](README_ja.md)* 10 | 11 | # Next Forge - 多言語対応 Next.js 15 スターター 12 | 13 | グローバル対応のウェブサイトを素早く構築するための、機能豊富なNext.js 15多言語スターターテンプレートです。 14 | 15 | - [👉 ソースコード](https://github.com/weijunext/nextjs-15-starter) 16 | - [👉 デモサイト](https://nextforge.dev/) 17 | 18 | **🚀 多機能で使いやすいフルスタックの起動テンプレートをお探しですか? ぜひ、当社の[アドバンス版](https://nexty.dev)をお試しください。** 19 | 20 | ## ✨ 主な機能 21 | 22 | - 🌐 多言語対応(英語・中国語・日本語) 23 | - 🎨 Tailwind CSSによるモダンなUI 24 | - 🌙 ダーク/ライトテーマ切り替え 25 | - 📱 レスポンシブデザイン 26 | - 📝 MDXブログシステム 27 | - 🔍 SEO最適化 28 | - 📊 アナリティクスツール統合 29 | - Google Analytics 30 | - Baidu Analytics 31 | - Google Adsense 32 | - Vercel Analytics 33 | 34 | ## 🚀 クイックスタート 35 | 36 | ### 必要な環境 37 | 38 | - Node.js 18.17 以上 39 | - pnpm 9.0 以上(推奨) 40 | 41 | > **注意**: プロジェクトには `packageManager` フィールドが設定されており、最適な体験のために pnpm の使用を推奨しています。 42 | 43 | ### インストール手順 44 | 45 | 1. リポジトリのクローン: 46 | ```bash 47 | git clone https://github.com/weijunext/nextjs-15-starter.git 48 | cd nextjs-15-starter 49 | ``` 50 | 51 | 2. Corepack の有効化(推奨): 52 | ```bash 53 | corepack enable 54 | ``` 55 | 56 | 3. 依存関係のインストール: 57 | ```bash 58 | pnpm install 59 | # または他のパッケージマネージャーを使用 60 | npm install 61 | yarn 62 | ``` 63 | 64 | 4. 環境変数の設定: 65 | ```bash 66 | cp .env.example .env 67 | ``` 68 | 69 | 5. 開発サーバーの起動: 70 | ```bash 71 | pnpm dev 72 | # または npm run dev 73 | ``` 74 | 75 | http://localhost:3000 にアクセスして確認できます。 76 | 77 | ## ⚙️ 設定方法 78 | 79 | 1. 基本設定 80 | - `config/site.ts`でウェブサイト情報を編集 81 | - `public/`内のアイコンとロゴを更新 82 | - `app/sitemap.ts`でサイトマップを設定 83 | - `app/robots.ts`でrobots.txtを更新 84 | 85 | 2. 多言語設定 86 | - `i18n/messages/`内の言語ファイルを追加/編集 87 | - `i18n/routing.ts`でサポートする言語を設定 88 | - `middleware.ts`で多言語ルーティングを設定 89 | - `app/[locale]/`配下にページを作成 90 | - Next.jsデフォルトの代わりに`i18n/routing.ts`の`Link`コンポーネントを使用 91 | 92 | ## 📝 コンテンツ管理 93 | 94 | ### ブログ投稿 95 | `blog/[locale]`にMDXファイルを以下のフォーマットで作成: 96 | 97 | ```markdown 98 | --- 99 | title: 投稿タイトル 100 | description: 投稿の説明 101 | image: /image.png 102 | slug: /url-path 103 | tags: tag1,tag2 104 | date: 2025-02-20 105 | visible: published 106 | pin: true 107 | --- 108 | 109 | 投稿内容... 110 | ``` 111 | 112 | 対応フィールドについては`types/blog.ts`を参照してください。 113 | 114 | ### 静的ページ 115 | `content/[page]/[locale].mdx`で静的ページのコンテンツを管理します。 116 | 117 | ## 🔍 SEO最適化 118 | 119 | 包括的なSEO機能を搭載: 120 | - サーバーサイドレンダリングと静的生成 121 | - sitemap.xml自動生成 122 | - robots.txt設定 123 | - 最適化されたメタデータ 124 | - OGP対応 125 | - 多言語SEOサポート 126 | 127 | ## 📊 アナリティクス 128 | 129 | `.env`にIDを追加して有効化: 130 | ``` 131 | NEXT_PUBLIC_GOOGLE_ANALYTICS= 132 | NEXT_PUBLIC_BAIDU_TONGJI= 133 | NEXT_PUBLIC_GOOGLE_ADSENSE= 134 | ``` 135 | 136 | ## 📁 プロジェクト構成 137 | 138 | ``` 139 | nextjs-15-starter/ 140 | ├── app/ # アプリディレクトリ 141 | │ ├── [locale]/ # 多言語ルート 142 | │ │ ├── about/ # Aboutページ 143 | │ │ ├── blog/ # ブログページ 144 | │ │ └── ... # その他のページ 145 | │ ├── api/ # APIルート 146 | │ └── globals/ # グローバルコンポーネント 147 | ├── blog/ # ブログコンテンツ(MDX) 148 | │ ├── en/ # 英語ブログ 149 | │ ├── ja/ # 日本語ブログ 150 | │ └── zh/ # 中国語ブログ 151 | ├── components/ # 再利用可能なコンポーネント 152 | │ ├── ui/ # ベースUIコンポーネント 153 | │ ├── header/ # ヘッダーコンポーネント 154 | │ ├── footer/ # フッターコンポーネント 155 | │ └── ... # その他のコンポーネント 156 | ├── config/ # 設定ファイル 157 | ├── content/ # 静的コンテンツ(MDX) 158 | ├── i18n/ # 国際化設定 159 | │ ├── messages/ # 翻訳ファイル 160 | │ ├── routing.ts # ルーティング設定 161 | │ └── request.ts # リクエスト設定 162 | ├── lib/ # ユーティリティ関数 163 | ├── public/ # 静的アセット 164 | └── types/ # 型定義 165 | ``` 166 | 167 | ## 🛠️ 技術スタック 168 | 169 | - **フレームワーク**: Next.js 15 (App Router) 170 | - **言語**: TypeScript 171 | - **スタイリング**: Tailwind CSS + Shadcn/ui 172 | - **国際化**: next-intl 173 | - **コンテンツ**: MDX 174 | - **状態管理**: Zustand 175 | - **デプロイ**: Vercel 176 | - **パッケージマネージャー**: pnpm(推奨) 177 | 178 | ## 🚀 デプロイ 179 | 180 | ### ワンクリックデプロイ 181 | 182 | [![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/weijunext/nextjs-15-starter&project-name=&repository-name=nextjs-15-starter&demo-title=Nextjs15Starter&demo-description=Nextjs%2015%20starter.&demo-url=https://nextforge.dev&demo-image=https://nextforge.dev/og.png) 183 | 184 | ### Vercelへの手動デプロイ 185 | 186 | 1. GitHubにコードをプッシュ 187 | 2. Vercelでプロジェクトをインポート 188 | 3. 環境変数を設定 189 | 4. デプロイ 190 | 191 | ### その他のプラットフォーム 192 | 193 | ```bash 194 | # プロダクション用ビルド 195 | pnpm build 196 | 197 | # プロダクションサーバーを起動 198 | pnpm start 199 | ``` 200 | 201 | ## 💡 開発のベストプラクティス 202 | 203 | ### パッケージマネージャー使用 204 | 205 | - プロジェクトは `packageManager: "pnpm@10.12.4"` で設定済み 206 | - Corepack を有効化: `corepack enable` 207 | - チームメンバーは同じ pnpm バージョンを使用すべき 208 | 209 | ### コード品質 210 | 211 | ```bash 212 | # コードリント 213 | pnpm lint 214 | 215 | # 型チェック 216 | pnpm type-check 217 | ``` 218 | 219 | ### 多言語開発 220 | 221 | 1. 新しい言語サポートの追加: 222 | - `i18n/messages/` に新しい言語ファイルを追加 223 | - `i18n/routing.ts` 設定を更新 224 | - `blog/` と `content/` に対応する言語ディレクトリを作成 225 | 226 | 2. 翻訳の使用: 227 | ```tsx 228 | import { useTranslations } from 'next-intl'; 229 | 230 | export default function MyComponent() { 231 | const t = useTranslations('namespace'); 232 | return

{t('title')}

; 233 | } 234 | ``` 235 | 236 | ## 🔧 トラブルシューティング 237 | 238 | ### よくある問題 239 | 240 | **1. パッケージマネージャーのバージョン不一致** 241 | ```bash 242 | # node_modules と lockfile を削除 243 | rm -rf node_modules pnpm-lock.yaml 244 | # 再インストール 245 | pnpm install 246 | ``` 247 | 248 | **2. MDXファイルが表示されない** 249 | - ファイルパスが正しいか確認 250 | - frontmatter のフォーマットが正しいか確認 251 | - `visible` フィールドが `published` に設定されているか確認 252 | 253 | **3. 多言語ルーティングの問題** 254 | - `i18n/routing.ts` の `Link` コンポーネントを使用 255 | - `middleware.ts` の設定を確認 256 | 257 | **4. スタイルが効かない** 258 | - Tailwind CSS のクラス名が正しいか確認 259 | - 開発サーバーの再起動を試す 260 | 261 | ### 環境変数の問題 262 | 263 | `.env` ファイルに必要な設定が含まれていることを確認: 264 | ```bash 265 | # サンプル設定をコピー 266 | cp .env.example .env 267 | # 必要に応じて設定を変更 268 | ``` 269 | 270 | ## 📄 ライセンス 271 | 272 | MIT 273 | 274 | ## 🤝 コントリビューション 275 | 276 | Issue、PRは大歓迎です! 277 | 278 | ## 作者について 279 | 280 | Next.jsのフルスタックスペシャリストとして、プロジェクト開発、パフォーマンス最適化、SEO改善のエキスパートサービスを提供しています。 281 | 282 | コンサルティングやトレーニングについては、 weijunext@gmail.com までご連絡ください。 283 | 284 | - [Github](https://github.com/weijunext) 285 | - [Bento](https://bento.me/weijunext) 286 | - [Twitter/X](https://twitter.com/judewei_dev) 287 | 288 | Buy Me A Coffee 289 | 290 | [![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/G2G6TWWMG) -------------------------------------------------------------------------------- /README_zh.md: -------------------------------------------------------------------------------- 1 | --- 2 | 使用 Nexty 加速 SaaS 开发 - 唯一一个集成可视化定价面板、AI 开发环境和企业级 CMS 的 Next.js 模板,还包含多语言支持、身份验证、支付系统、电子邮件功能和 SEO 优化。 3 | 4 | 立即体验 [Nexty.dev](https://nexty.dev/?utm_source=github-nextjs-starter) 5 | --- 6 | 7 | [](https://nexty.dev/?utm_source=github-nextjs-starter) 8 | 9 | 🌍 *[English](README.md) ∙ [简体中文](README_zh.md) ∙ [日本语](README_ja.md)* 10 | 11 | # Next Forge - 多语言 Next.js 15 启动模板 12 | 13 | 一个轻量的 Next.js 15 多语言启动模板,帮助你快速构建面向全球的网站。 14 | 15 | - [👉 源码地址](https://github.com/weijunext/nextjs-15-starter) 16 | - [👉 在线预览](https://nextforge.dev/) 17 | 18 | **🚀 如果你正在寻找功能完备的全栈启动模板,请了解我们的[高级版](https://nexty.dev/?utm_source=github-nextjs-starter)** 19 | 20 | ## ✨ 特性 21 | 22 | - 🌐 内置多语言支持 (中文、英文、日语) 23 | - 🎨 基于 Tailwind CSS 的现代 UI 设计 24 | - 🌙 深色/浅色主题切换 25 | - 📱 响应式布局 26 | - 📝 MDX 博客系统 27 | - 🔍 SEO 优化 28 | - 📊 集成多个统计分析工具 29 | - Google Analytics 30 | - Baidu Analytics 31 | - Google Adsense 32 | - Vercel Analytics 33 | 34 | ## 🚀 快速开始 35 | 36 | ### 环境要求 37 | 38 | - Node.js 18.17 或更高版本 39 | - pnpm 9.0 或更高版本(推荐) 40 | 41 | > **注意**: 项目已配置 `packageManager` 字段,推荐使用 pnpm 以获得最佳体验。 42 | 43 | ### 安装步骤 44 | 45 | 1. 克隆项目: 46 | ```bash 47 | git clone https://github.com/weijunext/nextjs-15-starter.git 48 | cd nextjs-15-starter 49 | ``` 50 | 51 | 2. 启用 Corepack (推荐): 52 | ```bash 53 | corepack enable 54 | ``` 55 | 56 | 3. 安装依赖: 57 | ```bash 58 | pnpm install 59 | # 或使用其他包管理器 60 | npm install 61 | yarn 62 | ``` 63 | 64 | 4. 复制环境变量文件: 65 | ```bash 66 | cp .env.example .env 67 | ``` 68 | 69 | 5. 启动开发服务器: 70 | ```bash 71 | pnpm dev 72 | # 或 npm run dev 73 | ``` 74 | 75 | 访问 http://localhost:3000 查看你的应用。 76 | 77 | ## ⚙️ 配置 78 | 79 | 1. 基础配置 80 | - 修改 `config/site.ts` 配置网站信息 81 | - 修改 `public/` 下的图标和 logo 82 | - 更新 `app/sitemap.ts` 配置站点地图 83 | - 更新 `app/robots.ts` 配置 robots.txt 84 | 85 | 2. 多语言配置 86 | - 在 `i18n/messages/` 下添加或修改语言文件 87 | - 在 `i18n/routing.ts` 中配置支持的语言 88 | - 在 `middleware.ts` 中配置多语言路由 89 | - 在 `app/[locale]/` 目录下创建页面 90 | - 多语言页面使用 `i18n/routing.ts` 导出的 `Link` 组件替代 next.js 的 91 | 92 | ## 📝 内容管理 93 | 94 | ### 博客文章 95 | 在 `blog/[locale]` 目录下创建 MDX 文件,支持以下格式: 96 | 97 | ```markdown 98 | --- 99 | title: 文章标题 100 | description: 文章描述 101 | image: /image.png 102 | slug: /url-path 103 | tags: tag1,tag2 104 | date: 2025-02-20 105 | visible: published 106 | pin: true 107 | --- 108 | 109 | 文章内容... 110 | ``` 111 | 112 | 可参考类型定义 `types/blog.ts` 确认支持的字段。 113 | 114 | ### 静态页面 115 | 在 `content/[page]/[locale].mdx` 下管理静态页面内容。 116 | 117 | ## 🔍 SEO 优化 118 | 119 | 模板内置了完整的 SEO 优化方案: 120 | - 服务端渲染和静态生成 121 | - 自动生成 sitemap.xml 122 | - 配置 robots.txt 123 | - 优化的 metadata 124 | - 支持 Open Graph 125 | - 多语言 SEO 支持 126 | 127 | ## 📊 统计分析 128 | 129 | 在 `.env` 文件中配置相应的 ID 即可启用: 130 | ``` 131 | NEXT_PUBLIC_GOOGLE_ANALYTICS= 132 | NEXT_PUBLIC_BAIDU_TONGJI= 133 | NEXT_PUBLIC_GOOGLE_ADSENSE= 134 | ``` 135 | 136 | ## 📁 项目结构 137 | 138 | ``` 139 | nextjs-15-starter/ 140 | ├── app/ # 应用路由目录 141 | │ ├── [locale]/ # 多语言路由 142 | │ │ ├── about/ # 关于页面 143 | │ │ ├── blog/ # 博客页面 144 | │ │ └── ... # 其他页面 145 | │ ├── api/ # API 路由 146 | │ └── globals/ # 全局组件 147 | ├── blog/ # 博客内容 (MDX) 148 | │ ├── en/ # 英文博客 149 | │ ├── ja/ # 日文博客 150 | │ └── zh/ # 中文博客 151 | ├── components/ # 可复用组件 152 | │ ├── ui/ # 基础 UI 组件 153 | │ ├── header/ # 头部组件 154 | │ ├── footer/ # 底部组件 155 | │ └── ... # 其他组件 156 | ├── config/ # 配置文件 157 | ├── content/ # 静态内容 (MDX) 158 | ├── i18n/ # 国际化配置 159 | │ ├── messages/ # 翻译文件 160 | │ ├── routing.ts # 路由配置 161 | │ └── request.ts # 请求配置 162 | ├── lib/ # 工具函数 163 | ├── public/ # 静态资源 164 | └── types/ # 类型定义 165 | ``` 166 | 167 | ## 🛠️ 技术栈 168 | 169 | - **框架**: Next.js 15 (App Router) 170 | - **语言**: TypeScript 171 | - **样式**: Tailwind CSS + Shadcn/ui 172 | - **国际化**: next-intl 173 | - **内容**: MDX 174 | - **状态管理**: Zustand 175 | - **部署**: Vercel 176 | - **包管理器**: pnpm (推荐) 177 | 178 | 179 | ## 🚀 部署 180 | 181 | ### 一键部署 182 | 183 | [![Deploy with Vercel](https://vercel.com/button)](https://vercel.com/new/clone?repository-url=https://github.com/weijunext/nextjs-15-starter&project-name=&repository-name=nextjs-15-starter&demo-title=Nextjs15Starter&demo-description=Nextjs%2015%20starter.&demo-url=https://nextforge.dev&demo-image=https://nextforge.dev/og.png) 184 | 185 | ### 手动部署到 Vercel 186 | 187 | 1. 推送代码到 GitHub 188 | 2. 在 Vercel 中导入项目 189 | 3. 配置环境变量 190 | 4. 部署 191 | 192 | ### 其他平台部署 193 | 194 | ```bash 195 | # 构建生产版本 196 | pnpm build 197 | 198 | # 启动生产服务器 199 | pnpm start 200 | ``` 201 | 202 | ## 💡 开发最佳实践 203 | 204 | ### 包管理器使用 205 | 206 | - 项目已配置 `packageManager: "pnpm@10.12.4"` 207 | - 建议启用 Corepack: `corepack enable` 208 | - 团队成员应使用相同版本的 pnpm 209 | 210 | ### 代码规范 211 | 212 | ```bash 213 | # 代码检查 214 | pnpm lint 215 | 216 | # 类型检查 217 | pnpm type-check 218 | ``` 219 | 220 | ### 多语言开发 221 | 222 | 1. 新增语言支持: 223 | - 在 `i18n/messages/` 添加新的语言文件 224 | - 更新 `i18n/routing.ts` 配置 225 | - 在 `blog/` 和 `content/` 下创建对应语言目录 226 | 227 | 2. 使用翻译: 228 | ```tsx 229 | import { useTranslations } from 'next-intl'; 230 | 231 | export default function MyComponent() { 232 | const t = useTranslations('namespace'); 233 | return

{t('title')}

; 234 | } 235 | ``` 236 | 237 | ## 🔧 故障排除 238 | 239 | ### 常见问题 240 | 241 | **1. 包管理器版本不一致** 242 | ```bash 243 | # 删除 node_modules 和 lockfile 244 | rm -rf node_modules pnpm-lock.yaml 245 | # 重新安装 246 | pnpm install 247 | ``` 248 | 249 | **2. MDX 文件不显示** 250 | - 检查文件路径是否正确 251 | - 确认 frontmatter 格式正确 252 | - 检查 `visible` 字段是否设置为 `published` 253 | 254 | **3. 多语言路由问题** 255 | - 确保使用 `i18n/routing.ts` 中的 `Link` 组件 256 | - 检查 `middleware.ts` 配置 257 | 258 | **4. 样式不生效** 259 | - 确认 Tailwind CSS 类名拼写正确 260 | - 检查是否需要重启开发服务器 261 | 262 | ### 环境变量问题 263 | 264 | 确保 `.env` 文件包含必要的配置: 265 | ```bash 266 | # 复制示例配置 267 | cp .env.example .env 268 | # 根据需要修改配置 269 | ``` 270 | 271 | 272 | ## 📄 许可证 273 | 274 | MIT 275 | 276 | ## 🤝 贡献 277 | 278 | 欢迎提交 Issue 和 Pull Request! 279 | 280 | ## 关于作者 281 | 282 | 专注于 Next.js 全栈开发,欢迎探讨开发、咨询与培训等合作机会,联系微信:bigye_chengpu 283 | 284 | - [Github](https://github.com/weijunext) 285 | - [Twitter/X](https://twitter.com/weijunext) 286 | - [博客 - J实验室](https://weijunext.com) 287 | - [Medium](https://medium.com/@weijunext) 288 | - [掘金](https://juejin.cn/user/26044008768029) 289 | - [知乎](https://www.zhihu.com/people/mo-mo-mo-89-12-11) 290 | 291 | Buy Me A Coffee 292 | 293 | [![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/G2G6TWWMG) 294 | 295 | 赞赏作者 296 | 297 | 298 | -------------------------------------------------------------------------------- /actions/newsletter.ts: -------------------------------------------------------------------------------- 1 | import { normalizeEmail, validateEmail } from '@/lib/email'; 2 | import { Ratelimit } from '@upstash/ratelimit'; 3 | import { Redis } from '@upstash/redis'; 4 | import { headers } from 'next/headers'; 5 | import { Resend } from 'resend'; 6 | 7 | // initialize resend 8 | const resend = new Resend(process.env.RESEND_API_KEY); 9 | 10 | // Resend Audience ID 11 | const AUDIENCE_ID = process.env.RESEND_AUDIENCE_ID!; 12 | 13 | // initialize Redis 14 | const redis = new Redis({ 15 | url: process.env.UPSTASH_REDIS_REST_URL!, 16 | token: process.env.UPSTASH_REDIS_REST_TOKEN!, 17 | }); 18 | 19 | const REDIS_RATE_LIMIT_KEY = process.env.UPSTASH_REDIS_NEWSLETTER_RATE_LIMIT_KEY!; 20 | const DAY_MAX_SUBMISSIONS = parseInt(process.env.DAY_MAX_SUBMISSIONS || '10'); 21 | 22 | // create rate limiter 23 | const limiter = new Ratelimit({ 24 | redis, 25 | limiter: Ratelimit.slidingWindow(DAY_MAX_SUBMISSIONS, '1d'), 26 | prefix: REDIS_RATE_LIMIT_KEY, 27 | }); 28 | 29 | // Shared rate limit check 30 | async function checkRateLimit() { 31 | const headersList = await headers(); 32 | const ip = headersList.get('x-real-ip') || 33 | headersList.get('x-forwarded-for') || 34 | 'unknown'; 35 | 36 | const { success } = await limiter.limit(ip); 37 | if (!success) { 38 | throw new Error('Too many submissions, please try again later'); 39 | } 40 | } 41 | 42 | export async function subscribeToNewsletter(email: string) { 43 | try { 44 | await checkRateLimit(); 45 | 46 | const normalizedEmail = normalizeEmail(email); 47 | const { isValid, error } = validateEmail(normalizedEmail); 48 | 49 | if (!isValid) { 50 | throw new Error(error || 'Invalid email address'); 51 | } 52 | 53 | // Check if already subscribed 54 | // const list = await resend.contacts.list({ audienceId: AUDIENCE_ID }); 55 | // const user = list.data?.data.find((item) => item.email === normalizedEmail); 56 | // if (user) { 57 | // return { success: true, alreadySubscribed: true }; 58 | // } 59 | 60 | // Add to audience 61 | await resend.contacts.create({ 62 | audienceId: AUDIENCE_ID, 63 | email: normalizedEmail, 64 | }); 65 | 66 | // Send welcome email 67 | const unsubscribeToken = Buffer.from(normalizedEmail).toString('base64'); 68 | const unsubscribeLink = `${process.env.NEXT_PUBLIC_SITE_URL}/unsubscribe?token=${unsubscribeToken}`; 69 | 70 | await resend.emails.send({ 71 | from: 'NextForge <' + process.env.ADMIN_EMAIL! + '>', 72 | to: normalizedEmail, 73 | subject: 'Welcome to Next Forge', 74 | html: ` 75 |

Welcome to Next Forge

76 |

Thank you for subscribing to the newsletter. You will receive the latest updates and news.

77 |

78 | If you wish to unsubscribe, please click here 79 |

80 | `, 81 | headers: { 82 | "List-Unsubscribe": `<${unsubscribeLink}>`, 83 | "List-Unsubscribe-Post": "List-Unsubscribe=One-Click" 84 | } 85 | }); 86 | 87 | return { success: true }; 88 | } catch (error) { 89 | console.error('Newsletter subscription failed:', error); 90 | throw error; 91 | } 92 | } 93 | 94 | export async function unsubscribeFromNewsletter(token: string) { 95 | try { 96 | await checkRateLimit(); 97 | 98 | const email = Buffer.from(token, 'base64').toString(); 99 | const normalizedEmail = normalizeEmail(email); 100 | const { isValid, error } = validateEmail(normalizedEmail); 101 | 102 | if (!isValid) { 103 | throw new Error(error || 'Invalid email address'); 104 | } 105 | 106 | // Check if subscribed 107 | const list = await resend.contacts.list({ audienceId: AUDIENCE_ID }); 108 | const user = list.data?.data.find((item) => item.email === normalizedEmail); 109 | 110 | if (!user) { 111 | throw new Error('This email is not subscribed to our notifications'); 112 | } 113 | 114 | // Remove from audience 115 | await resend.contacts.remove({ 116 | audienceId: AUDIENCE_ID, 117 | email: normalizedEmail, 118 | }); 119 | 120 | return { success: true, email: normalizedEmail }; 121 | } catch (error) { 122 | console.error('Newsletter unsubscribe failed:', error); 123 | throw error; 124 | } 125 | } -------------------------------------------------------------------------------- /app/BaiDuAnalytics.tsx: -------------------------------------------------------------------------------- 1 | "use client"; 2 | 3 | import Script from "next/script"; 4 | 5 | const BaiDuAnalytics = () => { 6 | return ( 7 | <> 8 | {process.env.NEXT_PUBLIC_BAIDU_TONGJI ? ( 9 | <> 10 |