s0vers/next-app-i18n-starter
s0vers/next-app-i18n-starter has 66 GitHub stars and 13 forks. GitHot measured 0 stars in 24 hours. Last checked 2026-11-15 16:01 UTC. Last push 2026-11-07.
What you can do
- Framework - Next.js 16 App Router, Server Components, Turbopack dev server
- i18n - next-intl 4: ICU messages, useFormatter, and locale-driven formatting
- Languages - English, Arabic (RTL), Chinese, Spanish, Japanese
- Formatting - Locale-based currency, dates, compact numbers, and relative time
Measured star growth
- in 24h
- 0
- in 7 days
- Collecting history
- in 15 days
- Collecting history
- in 1 month
- Collecting history
Net star changes over overlapping periods, not daily totals. Missing measurements are left blank. Stars measure attention, not software quality.
About
A humble Next.js 16 starter: Server Components, i18n with middleware, shadcn UI, light/dark themes with CSS variables, language switch, OmitRTL utility, and App Router. Jumpstart your modern web app with zero client-side JavaScript overhead.
Web & AppsREADME.md
OriginalNext.js 16 i18n Starter
A multilingual Next.js starter built with Next.js 16, React 19, next-intl 4, and shadcn/ui. It includes locale-driven formatting, Arabic RTL support, cookie-based light/dark mode, and SEO metadata for every locale.
Author: Sovers Tonmoy Pandey (s0vers) · GitHub · @s0ver5
Live demo: next-app-i18n-starter.vercel.app
New to i18n in Next.js? Start with the ten minute guide. It traces one request end to end, lists the mistakes this repository already made, and gives six exercises that break things on purpose.
Table of contents
- Features
- Prerequisites
- Getting started
- Project structure
- Skills for coding assistants
- Internationalization
- OmitRTL
- Theme system
- Typography and motion
- SEO
- Environment variables
- Deployment
- Scripts
- Troubleshooting
- Contributing
- License
- Acknowledgments
Features
| Area | What's included |
|---|---|
| Framework | Next.js 16 App Router, Server Components, Turbopack dev server |
| i18n | next-intl 4: ICU messages, useFormatter, and locale-driven formatting |
| Languages | English, Arabic (RTL), Chinese, Spanish, Japanese |
| Formatting | Locale-based currency, dates, compact numbers, and relative time |
| UI | shadcn/ui (base-nova style) on Base UI, Tailwind CSS 4, light/dark theme |
| RTL | Automatic dir="rtl" for Arabic + OmitRTL utility for LTR islands |
| SEO | metadataBase, hreflang, JSON-LD, sitemap/robots, OG image |
| DX | TypeScript, typed translation keys via global.d.ts, ESLint flat config |
Prerequisites
- Node.js 24.x (see
.nvmrc) - Bun 1.x
- Basic familiarity with Next.js App Router and React Server Components
Getting started
# Clone
git clone https://github.com/s0vers/next-app-i18n-starter.git
cd next-app-i18n-starter
# Install
bun install
# Set this project's public URL for local SEO preview (forks should replace it)
cp .env.example .env.local
# NEXT_PUBLIC_SITE_URL=https://next-app-i18n-starter.vercel.app
# Run
bun run dev
Open http://localhost:3000. Use the language switcher in the header to see translations and regional formatting update.
Before deploying a fork, set NEXT_PUBLIC_SITE_URL, update the site and author details in src/lib/site.ts, and replace the Open Graph image. Set GOOGLE_SITE_VERIFICATION if your Search Console property uses meta-tag verification. See the production SEO checklist.
Project structure
next-app-i18n-starter/
├── dictionary/ # Translation JSON files
│ ├── en.json # English (TypeScript source of truth)
│ ├── ar.json # Arabic
│ ├── zh.json # Chinese
│ ├── es.json # Spanish
│ └── ja.json # Japanese
├── public/
│ ├── llms.txt # Machine-readable context for AI tools
│ ├── og-image.png # Open Graph image (1200×630)
│ └── google52d37058772b10e6.html # Demo site's verification file
├── src/
│ ├── app/
│ │ ├── [locale]/ # All pages are locale-scoped
│ │ │ ├── layout.tsx # Metadata, theme SSR, providers, page shell
│ │ │ ├── page.tsx # Home + JSON-LD structured data
│ │ │ ├── not-found.tsx # Localized 404
│ │ │ ├── error.tsx # Localized error boundary
│ │ │ └── [...rest]/ # Catch-all → not-found
│ │ ├── global-error.tsx # Last-resort error page (replaces the root layout)
│ │ ├── globals.css # Tailwind + CSS variables
│ │ ├── favicon.ico # Site icon
│ │ ├── robots.ts # Dynamic robots.txt
│ │ └── sitemap.ts # Sitemap with hreflang alternates
│ ├── components/
│ │ ├── pages/HomeIndex.tsx # Landing page (hero + tabs), a Server Component
│ │ ├── CopyableCode.tsx # Copy button, the page's client island
│ │ ├── SiteHeader.tsx # Logo, language switcher, theme toggle (every page)
│ │ ├── SiteFooter.tsx # Footer (every page)
│ │ ├── LocalizationTab.tsx # Locale formatting demo
│ │ ├── LanguageSwitcher.tsx # Locale dropdown
│ │ ├── ModeToggle.tsx # Light/dark toggle
│ │ ├── OmitRtl.tsx # Forces LTR inside RTL pages
│ │ ├── theme-provider.tsx # Client theme context
│ │ └── ui/ # shadcn/ui primitives
│ ├── i18n/
│ │ ├── locales.ts # Locale labels and regional defaults
│ │ ├── request.ts # getRequestConfig (core i18n setup)
│ │ ├── routing.ts # Locales + URL prefix strategy
│ │ ├── regional.ts # Number and date format definitions
│ │ └── navigation.ts # Localized Link, useRouter, getPathname
│ ├── lib/
│ │ ├── site.ts # Site URL, author, SEO constants
│ │ ├── theme.ts # Theme cookie helpers
│ │ └── utils.ts # cn() class merge helper
│ └── proxy.ts # next-intl proxy (Next.js 16)
├── .agents/skills/ # next-intl and SEO skills: playbooks, scripts, evals
├── AGENTS.md # Shared instructions for coding assistants
├── CONTRIBUTING.md # How to set up and send a change
├── SECURITY.md # How to report a vulnerability
├── GUIDE.md # Ten minute tour of how i18n works here
├── .env.example
├── global.d.ts # next-intl AppConfig types
├── next.config.ts
├── package.json
└── tsconfig.json
Skills for coding assistants
This repository ships eight skills in .agents/skills/: one for next-intl and seven for SEO. They guide work on this starter and on forks. Each skill is a short SKILL.md that sends the agent to playbooks in its own references/ folder, and the agent loads only what the task needs. A skill installed on its own carries everything it needs, and the SEO skills name each other instead of linking. The playbooks cover products, blogs, and GA4, which the starter itself does not include.
next-intl-i18n
Locale routing, request config, messages, formatting, RTL and CJK layout, and localized content, checked against next-intl 4.14 and Next.js 16.3.
| Playbook | Covers |
|---|---|
| Architecture and rendering | Locale source decision, root params versus setRequestLocale, Cache Components, server and client split |
| Routing and navigation | Prefix modes, cookies, proxy, pathnames, domains, Link, locale switcher |
| Messages and formatting | ICU, rich text, formatters, typing, extraction |
| RTL and scripts | Arabic, Chinese, Japanese, Spanish: direction, numerals, plurals, fonts, line breaking |
| Localized content | CMS content, per-locale slugs, partial translation, adding a locale |
| Integrations and workflows | Metadata, Open Graph, Server Actions, error pages, tests |
| Verification | Done-when checks, symptom table, report shape |
Validate the locale registry (route keys, language tags, currency, time zone, direction, dictionary files) and check that every dictionary mirrors en.json (keys, ICU arguments, rich-text tags, plural other branches):
bun run i18n:check
The SEO skills
Search work is split into seven skills, so an agent loads only the one a task needs. Each has a narrow description that names what it is not for, and each keeps its playbooks in its own references/ folder. Every playbook dates its sources and tags each claim as documented, standard, study, practice, or unverified.
| Skill | Use it for |
|---|---|
| nextjs-seo-technical | Pages that are not indexed, robots, sitemap, canonicals, redirects, metadata, audits, launch checks, migrations. Holds verify-seo.mjs |
| nextjs-seo-international | hreflang, language tags, locale URLs, partial translation, the switcher, market launches, this starter's helpers |
| nextjs-seo-structured-data | JSON-LD, rich results, Product and Offer fields, removed features |
| nextjs-seo-commerce | Store URLs, facets, variants, stock states, currency markets, feeds |
| nextjs-seo-content | Blogs, articles, page copy, internal links, SaaS, docs, local, and other page types |
| nextjs-seo-measurement | Search Console, GA4, Bing, traffic-drop diagnosis |
| nextjs-seo-ai-search | AI Overviews, ChatGPT, Claude, Perplexity, AI crawler policy, llms.txt |
Check hreflang reciprocity, canonicals, lang, JSON-LD, sitemap agreement, and language redirects on a running site:
bun run dev
bun run seo:verify -- --base http://localhost:3000
For a production build served locally, add --origin https://your-domain.example so canonicals compare against the public origin. The script proves local implementation only. Indexing and canonical selection need Search Console.
Using the skills
In a clone of this repository, the instruction map in AGENTS.md points agents at the right skill. In your own project, install them with npx skills add s0vers/next-app-i18n-starter, which copies each skill into the folder your agent reads (Claude Code reads .claude/skills, and does not scan .agents/skills by itself). The skills are independent. Install only the ones you use, for example npx skills add s0vers/next-app-i18n-starter --skill nextjs-seo-technical, and each still works on its own. Otherwise, read the relevant SKILL.md and only the playbooks the task needs. Start with AGENTS.md for repository conventions. Each skill has an evals/evals.json with behavior prompts and assertions, plus at least eight should-trigger and eight near-miss prompts for testing its description. bun run skills:check enforces the minimum. Platform rules change, so recheck the owning platform's documentation for anything the playbooks date more than 90 days back.
Internationalization
This template uses next-intl with the App Router pattern. The i18n setup uses these files:
src/i18n/locales.ts: locale labels, currency, time zone, font, and Open Graph localesrc/i18n/routing.ts: URL prefix strategysrc/i18n/request.ts: per-request messages, time zone, and formatssrc/i18n/navigation.ts: locale-aware navigation wrappers
How routing works
Configured in src/i18n/routing.ts:
import { defineRouting } from "next-intl/routing";
import { locales } from "./locales";
export const routing = defineRouting({
locales,
defaultLocale: "en",
localeDetection: false,
localePrefix: "as-needed",
localeCookie: false,
alternateLinks: false,
});
localeCookie: false skips the NEXT_LOCALE cookie, which nothing reads while detection is off, and keeps Set-Cookie off cacheable pages. alternateLinks: false stops the proxy from adding its own hreflang Link header, so page metadata and the sitemap are the only source of alternates.
With localePrefix: "as-needed":
| Locale | URL | Notes |
|---|---|---|
en |
/ |
Default locale has no prefix |
ar |
/ar |
|
zh |
/zh |
|
es |
/es |
|
ja |
/ja |
src/proxy.ts routes locale-prefixed URLs and serves the default locale at /. Automatic locale detection from cookies or Accept-Language is disabled so the default URL stays stable; visitors can switch languages with the locale switcher.
Always use navigation from @/i18n/navigation, not next/link or next/navigation directly:
import { Link, useRouter, usePathname } from "@/i18n/navigation";
// Switch locale
const router = useRouter();
const pathname = usePathname();
router.replace(pathname, { locale: "ar" });
Locale-driven formatting
Currency, dates, and time zones follow the active locale. The demo does not provide separate controls for them.
src/i18n/locales.ts defines each locale's defaults:
| Locale | Currency | Time zone |
|---|---|---|
en |
USD | America/New_York |
ar |
SAR | Asia/Riyadh |
zh |
CNY | Asia/Shanghai |
es |
EUR | Europe/Madrid |
ja |
JPY | Asia/Tokyo |
src/i18n/request.ts applies them on every request:
export default getRequestConfig(async ({ locale }) => {
// Page renders read the locale from the [locale] route segment. Route
// Handlers and Server Actions pass one explicitly.
const requested = locale ?? (await rootParams.locale());
if (!hasLocale(routing.locales, requested)) notFound();
const { currency, timeZone } = localeConfig[requested];
return {
locale: requested,
timeZone,
now: new Date(),
formats: createRegionalFormats(currency),
messages: (await import(`../../dictionary/${requested}.json`)).default,
};
});
In components, use next-intl hooks:
"use client";
import { useFormatter, useNow } from "next-intl";
export function RegionalExamples() {
const format = useFormatter();
const now = useNow({ updateInterval: 30_000 });
const twoHoursAgo = new Date(now.getTime() - 2 * 60 * 60 * 1000);
return (
<div>
<p>{format.number(29.99, "price")}</p>
<p>{format.dateTime(now, "long")}</p>
<p>{format.relativeTime(twoHoursAgo, now)}</p>
</div>
);
}
In translation messages, use ICU syntax:
{
"priceMessage": "This product costs {price, number, currency}",
"usersCount": "{count, number, compact} users"
}
The Localization tab on the home page demonstrates these formats. Change the language in the header to see the prices and dates update.
Translation files
All strings live in dictionary/{locale}.json. Namespaces:
| Namespace | Used for |
|---|---|
Index |
Landing page UI, tabs, installation steps |
Footer |
Copyright, links |
Metadata |
Localized SEO title and description (generateMetadata) |
Localization |
Formatting demo tab labels |
NotFound |
Localized 404 page |
global.d.ts types locales, format names, and message keys from en.json:
import en from "./dictionary/en.json";
import type { AppLocale } from "./src/i18n/locales";
import { createRegionalFormats } from "./src/i18n/regional";
declare module "next-intl" {
interface AppConfig {
Locale: AppLocale;
Messages: typeof en;
Formats: ReturnType<typeof createRegionalFormats>;
}
}
Add each new key to every dictionary. TypeScript checks keys used in code against en.json; it does not compare the other JSON files automatically.
Server vs client components
Server Component (page or layout):
import { hasLocale } from "next-intl";
import { notFound } from "next/navigation";
import { getTranslations } from "next-intl/server";
import { routing } from "@/i18n/routing";
export default async function Page({ params }: { params: Promise<{ locale: string }> }) {
const { locale } = await params;
if (!hasLocale(routing.locales, locale)) notFound();
const t = await getTranslations({ locale, namespace: "Index" });
return <h1>{t("title")}</h1>;
}
Client Component:
"use client";
import { useTranslations } from "next-intl";
export function MyComponent() {
const t = useTranslations("Index");
return <p>{t("description")}</p>;
}
The root layout wraps children in NextIntlClientProvider with messages, timeZone, and now from the server.
Adding a new language
Example: adding French (fr)
Copy
dictionary/en.jsontodictionary/fr.jsonand translate every value.Add one entry to
localeConfiginsrc/i18n/locales.ts:fr: { label: "Français", languageTag: "fr", ogLocale: "fr_FR", currency: "EUR", timeZone: "Europe/Paris", dir: "ltr", font: "geist", },Routing, the language switcher, regional formatting, and Open Graph locale derive from this config. Choose
font: "system"if the Geist Latin subset does not cover the language.Run
bun run i18n:check,bun run lint, andbun run build, then check the new locale's page and metadata.i18n:checkvalidates the language tag, currency, time zone, and direction, and fails whenfr.jsonis missing a key or changes an ICU argument. TypeScript only checks keys againsten.json.
Adding a new page
// src/app/[locale]/about/page.tsx
import { hasLocale } from "next-intl";
import { notFound } from "next/navigation";
import { getTranslations } from "next-intl/server";
import { routing } from "@/i18n/routing";
export default async function AboutPage({
params,
}: {
params: Promise<{ locale: string }>;
}) {
const { locale } = await params;
if (!hasLocale(routing.locales, locale)) notFound();
const t = await getTranslations({ locale, namespace: "About" });
return <h1>{t("title")}</h1>;
}
Add "About" namespace to every dictionary/*.json. Link to it with:
import { Link } from "@/i18n/navigation";
<Link href="/about">{t("aboutLink")}</Link>
OmitRTL
Arabic sets dir="rtl" on <html>. Some content (code, terminal commands, logos, formatted numbers) should stay left-to-right.
Wrap those elements with OmitRTL:
import OmitRTL from "@/components/OmitRtl";
function CodeBlock({ code }: { code: string }) {
return (
<OmitRTL omitRTL>
<pre><code>{code}</code></pre>
</OmitRTL>
);
}
Import the default export from @/components/OmitRtl. The examples name it OmitRTL.
Theme system
The server reads the saved theme and renders the matching class before paint, avoiding a theme flash during hydration.
How it works
- Server (
layout.tsx) reads thethemecookie and setsclassName="light"or"dark"on<html>before paint. - Client (
theme-provider.tsx) updates the theme class and cookie when toggled. - Toggle (
ModeToggle.tsx) switches betweenlightanddark.
No blocking scripts. No next-themes dependency.
Typography and motion
src/i18n/locales.ts selects Geist for English and Spanish, and a system font for Arabic, Chinese, and Japanese. The layout loads the Geist Latin subset; change the locale's font setting when adding a language with different script coverage. Headings use balanced wrapping, while longer descriptions use readable line lengths and text-pretty.
Interactive controls have touch-sized targets and visible keyboard focus. Dropdowns use short enter and exit animations; keyboard-opened menus skip the entrance animation. The copy button only animates its icon for pointer input. Reduced-motion preferences disable those effects, and theme changes temporarily suppress color transitions so the whole page changes together.
SEO
Every locale page gets a self-canonical URL, reciprocal hreflang alternates, translated title and description, Open Graph and Twitter tags, and a sitemap entry. All of it comes from one place, so the pieces cannot drift apart.
| File | Responsibility |
|---|---|
src/lib/site.ts |
Site identity, validated origin, getLocaleUrl, getAlternateLanguages, createLocalizedMetadata |
src/app/[locale]/layout.tsx |
generateMetadata for each locale |
src/app/[locale]/page.tsx |
WebSite JSON-LD (default locale only) |
src/app/sitemap.ts, robots.ts |
/sitemap.xml with alternates, /robots.txt |
dictionary/{locale}.json |
Metadata.title and Metadata.description per locale |
English lives at / and the other locales at /{locale}, because routing uses localePrefix: "as-needed". Automatic locale detection is off, so cookies and browser language never redirect a URL. Each language is directly crawlable.
Add SEO to a new page
export async function generateMetadata({ params }: { params: Promise<{ locale: string }> }): Promise<Metadata> {
const { locale } = await params;
if (!hasLocale(routing.locales, locale)) notFound();
const t = await getTranslations({ locale, namespace: "About" });
return createLocalizedMetadata({
locale,
title: t("metaTitle"),
description: t("metaDescription"),
pathname: "/about",
});
}
Then add metaTitle and metaDescription to every dictionary, and one sitemap entry per locale with getAlternateLanguages("/about").
Before you launch a fork
- Set
NEXT_PUBLIC_SITE_URLto your HTTPS origin. Production builds reject placeholders. - Replace the site name, repository link, and author in
src/lib/site.ts. - Replace
public/og-image.png(1200×630) and translate theMetadatanamespace. - Set
GOOGLE_SITE_VERIFICATIONif you verify by meta tag, and remove the demo'spublic/google52d37058772b10e6.html. - Submit
/sitemap.xmlin Google Search Console and Bing Webmaster Tools. - Run
bun run seo:verify -- --base http://localhost:3000against a running build.
The SEO guide has the full reference: metadata fields, hreflang table, JSON-LD, sitemap and robots output, Open Graph, AI crawler policy, the complete launch checklist, and how to check each output. Nothing here guarantees indexing, rankings, or AI citations. Only Search Console and Bing report those.
Environment variables
| Variable | Required | Default | Description |
|---|---|---|---|
NEXT_PUBLIC_SITE_URL |
Production required | Project origin in .env.example; localhost fallback when unset in development; the deployment's own URL on Vercel preview deployments |
HTTPS origin for canonical URLs, sitemap, and social metadata |
GOOGLE_SITE_VERIFICATION |
No | Unset | Optional Search Console meta-tag verification token |
# .env.local
NEXT_PUBLIC_SITE_URL=https://next-app-i18n-starter.vercel.app
# Optional
GOOGLE_SITE_VERIFICATION=your-search-console-token
See .env.example for the template.
On Vercel, preview deployments (every pull request) build without NEXT_PUBLIC_SITE_URL when it is set for Production only, so src/lib/site.ts uses the preview's own VERCEL_URL. Production builds and other hosts still fail without the variable, which is deliberate: a missing value there would publish canonical URLs on the wrong domain. If you deploy previews somewhere else, set the variable for that environment too.
Deployment
Works on Vercel out of the box.
- Push to GitHub
- Import project in Vercel
- Set
NEXT_PUBLIC_SITE_URLtohttps://next-app-i18n-starter.vercel.appfor this project; forks must use their own production origin - Deploy
The proxy (src/proxy.ts) runs on the Node.js runtime, which is the Next.js 16 default. No extra configuration is needed for i18n routing.
Security headers
next.config.ts sends X-Content-Type-Options, Referrer-Policy, X-Frame-Options, and Permissions-Policy. src/proxy.ts sets a nonce-based Content-Security-Policy that allows only your own origin, and it needs pages to render dynamically (the theme cookie already makes them dynamic). When you add a script, font, image, or API host, add it to buildCsp. Set REPORT_ONLY = true while you test, so violations show in the browser console instead of being blocked, and check both with curl -I and the console. See SECURITY.md.
For other hosts, configure:
- Node.js 24+
- Run
bun run build, then start the server withbun run startor the host's equivalent command. - All locale paths (
/,/ar,/zh, etc.) route to the Next.js server
Scripts
bun run dev # Start the development server (Turbopack)
bun run build # Build for production
bun run start # Start the production server
bun run lint # Run ESLint
bun run typecheck # Run the TypeScript compiler without emitting
bun run check # ESLint, types, locale registry and message parity, and skills structure
GitHub Actions runs lint, the typecheck, bun run i18n:check, bun run skills:check, the build, and node .agents/skills/nextjs-seo-technical/scripts/verify-seo.mjs against the production build on every push and pull request. A second workflow opens a monthly issue listing skill references whose sources are older than 90 days and any drift from the latest next and next-intl. In a fork, set NEXT_PUBLIC_SITE_URL in .github/workflows/ci.yml to your own HTTPS origin.
Troubleshooting
Translations not updating after adding keys
Add the key to en.json and every other dictionary. TypeScript checks message keys used in code against en.json, but does not compare the other locale files automatically. Restart the dev server if an edited JSON file is not picked up.
Failed to load native binding or an SWC cache error on Windows
next-intl loads @swc/core from next.config.ts. From 1.16, SWC extracts its native addon into a cache folder and refuses any folder whose ancestors grant write rights to accounts other than yours. On Windows that rejects %LOCALAPPDATA%swc when an app package holds rights on AppDataLocal, and it rejects most folders on other drives, because they inherit Authenticated Users: Modify. The error is several levels deep in the cause of Failed to load native binding. It is reported upstream in swc-project/swc#12442.
This starter pins @swc/core to 1.15.33 through overrides in package.json, which loads its addon directly, so a fresh install works. If you remove the override, set SWC_NATIVE_BINDING_CACHE to a folder under your user profile, for example C:Users<you>.swc-cache, whose ancestors only you and administrators can write to. Remove the override once that issue is fixed and bun run build passes without it.
Wrong locale in URL
Check src/i18n/routing.ts. With localePrefix: "as-needed", only non-default locales have a prefix. English always uses /.
useTranslations returns wrong namespace
Check that the component is inside NextIntlClientProvider, which is set in the root layout, and that the namespace exists in the active locale's JSON file.
Theme flash on load
The server reads the theme cookie in layout.tsx and applies the class on <html> before rendering. Check that the cookie is light or dark and has path / if the initial theme is wrong.
hreflang URLs incorrect
Build alternate URLs with the helpers in @/lib/site, which use getPathname and respect localePrefix: "as-needed". English is /; it does not use /en. See SEO for the URL table.
JSON-LD not appearing
JSON-LD currently appears only on the default-locale home page (src/app/[locale]/page.tsx) and is rendered by a Server Component. View the page source and search for application/ld+json.
Wrong Open Graph image URL
Check that generateMetadata sets metadataBase and NEXT_PUBLIC_SITE_URL points to your domain. The Open Graph image path is relative: /og-image.png.
Sitemap shows wrong domain
Set NEXT_PUBLIC_SITE_URL in .env.local (dev) or Vercel environment variables (production). siteConfig.url drives all sitemap and robots URLs.
Metadata still in English on /ar
Check dictionary/ar.json has a translated Metadata namespace. generateMetadata calls getTranslations({ locale, namespace: "Metadata" }) with the route locale.
Contributing
- Fork the repository
- Create a branch:
git checkout -b feature/your-feature - Make changes. Update every dictionary file when adding translation keys.
- Verify:
bun run lint && bun run build - Commit:
git commit -am 'Add feature' - Push:
git push origin feature/your-feature - Open a Pull Request
License
MIT © Sovers Tonmoy Pandey
See LICENSE for details.
Acknowledgments
Open source libraries and community projects that made this starter possible: ACKNOWLEDGMENTS.md.
Instructions for coding assistants
The repository uses standard AGENTS.md files so coding assistants can follow the same project conventions across models and editors. Start with AGENTS.md, then read the nearest scoped guide for the files you are changing. The .cursor/rules/ files are optional Cursor adapters that point to those shared instructions.
Use the skills guide to choose the next-intl or SEO skill and its relevant playbook.
The public llms.txt is a project overview for tools that read it. Repository instructions live in AGENTS.md; llms.txt is not a Google Search ranking signal.