Open Source Next.js Saas Boilerplate
npx skills add https://github.com/revokslab/ShipFree --skill frontend-designInstallieren Sie diesen Skill über die CLI und beginnen Sie mit der Verwendung des SKILL.md-Workflows in Ihrem Arbeitsbereich.
Hi there! 👋
ShipFree is a free alternative to ShipFast, designed to simplify and optimize your shipping process. It’s built using modern web technologies like Next.js, Bun, Stripe, Drizzle ORM, Postgres and Tailwindcss.
For full documentation, visit: ShipFree Docs
Please read our Code of Conduct before contributing.
For people who want to contribute, please refer to CONTRIBUTING.md.
ShipFree includes internationalization support using next-intl with automatic locale routing. The template supports English (en), French (fr), and Spanish (es) out of the box.
The i18n/navigation.ts file exports internationalized versions of Next.js navigation components and hooks that automatically handle locale prefixes:
Link - Internationalized Link component that automatically prefixes routes with the current localeredirect - Server-side redirect function that preserves localeusePathname - Hook that returns the pathname without the locale prefixuseRouter - Hook for programmatic navigation with locale supportimport { Link } from '@/i18n/navigation'
// Automatically includes locale prefix (e.g., /en/about, /fr/about)
<Link href="/about">About</Link>
// Switch to a different locale
<Link href="/about" locale="fr">À propos</Link>
'use client'
import { useRouter, usePathname } from '@/i18n/navigation'
import { useLocale } from 'next-intl'
export function MyComponent() {
const router = useRouter()
const pathname = usePathname()
const locale = useLocale()
// Navigate to a route (automatically includes locale)
const handleClick = () => {
router.push('/dashboard')
}
// Switch locale for current page
const switchLanguage = (newLocale: string) => {
router.replace(pathname, { locale: newLocale })
}
return (
<div>
<p>Current locale: {locale}</p>
<p>Current pathname: {pathname}</p>
<button onClick={handleClick}>Go to Dashboard</button>
<button onClick={() => switchLanguage('fr')}>Switch to French</button>
</div>
)
}
// Server Component
import { getTranslations } from 'next-intl/server'
export default async function ServerPage() {
const t = await getTranslations('MyPage')
return <h1>{t('title')}</h1>
}
// Client Component
'use client'
import { useTranslations } from 'next-intl'
export default function ClientPage() {
const t = useTranslations('MyPage')
return <h1>{t('title')}</h1>
}
To add a new locale:
Add the locale to i18n/routing.ts:
locales: ['en', 'fr', 'es', 'de'], // Add 'de' for German
Create a translation file in messages/:
// messages/de.json
{
"PRICING": "Preise"
}
Update the localeNames object in components/language-switcher.tsx:
const localeNames: Record<string, string> = {
en: 'English',
fr: 'Français',
es: 'Español',
de: 'Deutsch', // Add German
}
All routes are automatically prefixed with the locale:
/ or /en → English homepage/fr → French homepage/es → Spanish homepage/en/about → English about page/fr/about → French about pageThe default locale (en) uses the as-needed prefix strategy, meaning it doesn't show the locale prefix in the URL when it's the default language.
This template includes a premium purchase feature that allows users to buy the Premium version of ShipFree. This feature is completely isolated from the template's payment system and can be easily removed if you don't need it.
The premium purchase feature is used to sell the Premium template itself ($90 one-time payment). It includes:
Important: This is separate from the template's built-in payment system (Stripe, Polar, Lemon Squeezy) which is used by your application to accept payments from your customers.
To completely remove the premium purchase feature:
Delete the following folders:
app/api/premium-purchase/app/api/webhooks/premium-purchase/ (if created)app/[locale]/(site)/premium-purchase/Delete the following files:
lib/premium-purchase.tslib/premium-purchase/hooks.tsapp/[locale]/(site)/pricing/premium-button.tsxUpdate app/[locale]/(site)/pricing.tsx:
import { PremiumButton } from './pricing/premium-button'<PremiumButton /> with a regular button or remove the button handler// Premium template purchase - can be removed if not neededRemove environment variables from config/env.ts:
PREMIUM_PURCHASE_ prefix:
PREMIUM_PURCHASE_STRIPE_SECRET_KEY (server)PREMIUM_PURCHASE_STRIPE_PRICE_ID (server)PREMIUM_PURCHASE_STRIPE_WEBHOOK_SECRET (server, optional)NEXT_PUBLIC_PREMIUM_PURCHASE_STRIPE_PUBLISHABLE_KEY (client)NEXT_PUBLIC_PREMIUM_PURCHASE_DISCORD_INVITE_LINK (client)Remove from .env file:
PREMIUM_PURCHASE_* environment variablesRemove webhook endpoint (if configured):
/api/webhooks/premium-purchaseAfter removal, the template's payment functionality (for your customers) will continue to work normally. The premium purchase feature is completely decoupled and does not affect any other features.
Cooked for you with ❤️ by Revoks