This is Next.js + EdgeDB starter project bootstraped on the T3 Stack
- Next.js Fullstack React framework using the app router
- EdgeDB Graph-relational database with a custom query language, Auth extension and more
- tRPC typesafe end-2-end API definition & access
- Tailwind CSS with Flowbite React componentss
- TypeScript language for JavaScript autocompletion
- i18next localization integrated with zod-i18n
- Storybook for building & testing UI in isolation
Note
Project uses unstable apis such as the EdgeDB auth extension
TBD
Set the allowed redirect url via the REPL (run edgedb
):
configure current database set ext::auth::AuthConfig::allowed_redirect_urls := {"http://localhost:3000/"}
- ✅ Works for client & server components and server actions.
- ✅ Support for active pathname checks via
useLngPathname()
. - ✅ Extraction of translation keys via
i18next-parser
. - ✅ Integrated with
zod
both for key translation & extraction including custom translation keys.
- Add your language code into options array.
- Import your
zod
translations and add into resources map - Run
npm run i18n
which will create empty folders & json maps for your locales from added in step 1. - Fill the translations & commit changes.
- 🎉 Your app is translated!
/**
* Use the custom RSC Params type which gives you the global `[lng]` param.
*/
import { Params } from "@/types";
/**
* Import the SSR translations hook from a local `i18n` folder.
* NOTE: the SSR hook is awaited!
*/
import { useTranslation } from "@/i18n";
export default async function Page({ params: { lng } }: Params) {
// Specify the feature name as your namespace.
// Use the "global" namespace for reusable components like Button.
const { t } = await useTranslation("feature", lng);
return <h1>{t("title")}</h1>;
}
You can also use this 'hook' in the server actions. See the auth actions as an example.
In client components, we use the hook useTranslation()
from a library.
import { useTranslation } from "react-i18next";
export function CreateUserForm() {
const { t } = useTranslation("onboarding");
}
On the client side, the import of translation files is handled in the RootLayout
by the <Language />
component.
Since the [lng]
param is present in every pathname
, we extend the usePathame()
from Next.js,
with a functionality to strip the prefix away, so you can check for active path easily:
"use client";
/**
* Import useLngPathname instead of the usePathname
*/
import { useLngPathname } from "@/i18n";
/**
* Get the type for prop which will be passed from the server component params.
*/
import { type LanguageParam } from "@/i18n";
export function Navbar({ lng }: LanguageParam) {
// pathname no longer contains the lng prefix!
const pathname = useLngPathname(lng);
const { t } = useTranslation("global");
// we can check if the path is active without worrying about the language:
return (
<nav>
<NavbarLink href="/dashboard" active={pathname.startsWith("/dashboard")}>
{t("dashboard")}
</NavbarLink>
</nav>
);
}
See full code of the <Navbar />
.
When you use .refine()
API of zod
, the custom error must be defined in params
as follows:
/**
* The local "t" function is necessary for the i18next-parser to extract the translation key properly.
*/
import { t } from "@/i18n";
const customError = z.string().refine((val) => val, {
// The "zodError" namespace here is mandatory & typechecked
// The actual key, will be passed down to the zod-i18n-map which will do the translation.
params: { i18n: t("zodError:passwordsMustMatch") },
});
See the translation of the passwordsMustMatch
refinement .
In development, the library automatically detects the linked edgedb project. In production EDGEDB_DSN
env variable is recommended.
TBD
This is related to ipv6 in Node18 (often on Windows 11).
- Make sure your
node -v
is equal to the one in.nvmrc
Run nvm use
to apply the project node version.
Run nvm alias default node
to make it default.
- Configure EdgeDB. See Source.
edgedb configure set listen_addresses 127.0.0.1 ::1