-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #90 from premieroctet/feature/i18n
Add i18n support
- Loading branch information
Showing
40 changed files
with
1,096 additions
and
175 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
"@premieroctet/next-admin": minor | ||
--- | ||
|
||
🌐 add i18n support |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
# I18n | ||
|
||
Next Admin supports i18n with the `translations` prop of the `NextAdmin` component. | ||
|
||
The following keys are accepted: | ||
|
||
| Name | Description | Default value | | ||
| ------------------------------- | ------------------------------------------------------------------------------------- | ------------------------- | | ||
| list.header.add.label | The "Add" button in the list header | Add | | ||
| list.header.search.placeholder | The placeholder used in the search input | Search | | ||
| list.footer.indicator.showing | The "Showing from" text in the list indicator, e.g: <u>Showing from</u> 1 to 10 of 25 | Showing from | | ||
| list.footer.indicator.to | The "to" text in the list indicator, e.g: Showing from 1 <u>to</u> 10 of 25 | to | | ||
| list.footer.indicator.of | The "of" text in the list indicator, e.g: Showing from 1 to 10 <u>of</u> 25 | of | | ||
| list.row.actions.delete.label | The text in the delete button displayed at the end of each row | Delete | | ||
| list.empty.label | The text displayed when there is no row in the list | No \{\{resource\}\} found | | ||
| form.button.save.label | The text displayed in the form submit button | Submit | | ||
| form.button.delete.label | The text displayed in the form delete button | Delete | | ||
| form.widgets.file_upload.label | The text displayed in file upload widget to select a file | Choose a file | | ||
| form.widgets.file_upload.delete | The text displayed in file upload widget to delete the current file | Delete | | ||
| actions.label | The text displayed in the dropdown button for the actions list | Action | | ||
| actions.delete.label | The text displayed for the default delete action in the actions dropdown | Delete | | ||
|
||
There is two ways to translate these default keys, provide a function named `getMessages` inside the options or provide `translations` props to `NextAdmin` component. | ||
> Note that the function way allows you to provide an object with a multiple level structure to translate the keys, while the `translations` props only allows you to provide a flat object (`form.widgets.file_upload.delete` ex.) | ||
You can also pass your own set of translations. For example you can set a custom action name as a translation key, which will then be translated by the lib. | ||
|
||
```js | ||
actions: [ | ||
{ | ||
title: "actions.user.email", | ||
action: async (...args) => { | ||
"use server"; | ||
const { submitEmail } = await import("./actions/nextadmin"); | ||
await submitEmail(...args); | ||
}, | ||
successMessage: "actions.user.email.success", | ||
errorMessage: "actions.user.email.error", | ||
}, | ||
], | ||
``` | ||
|
||
Here, the `actions.user.email` key will be translated by the lib, and the value will be used as the action title, aswell as the success and error messages after the action's execution. | ||
|
||
Currently, you can only translate the following: | ||
|
||
- action title, success and error message | ||
- field validation error message | ||
|
||
Check the example app for more details on the usage. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
import { NextAdmin } from "@premieroctet/next-admin"; | ||
import { getPropsFromParams } from "@premieroctet/next-admin/dist/appRouter"; | ||
import { getMessages } from "next-intl/server"; | ||
import { deleteItem, submitFormAction } from "../../../../actions/nextadmin"; | ||
import Dashboard from "../../../../components/Dashboard"; | ||
import { options } from "../../../../options"; | ||
import { prisma } from "../../../../prisma"; | ||
import schema from "../../../../prisma/json-schema/json-schema.json"; | ||
import "../../../../styles.css"; | ||
|
||
export default async function AdminPage({ | ||
params, | ||
searchParams, | ||
}: { | ||
params: { [key: string]: string[] | string }; | ||
searchParams: { [key: string]: string | string[] | undefined } | undefined; | ||
}) { | ||
const props = await getPropsFromParams({ | ||
params: params.nextadmin as string[], | ||
searchParams, | ||
options, | ||
prisma, | ||
schema, | ||
action: submitFormAction, | ||
deleteAction: deleteItem, | ||
getMessages: () => getMessages({ locale: params.locale as string }).then((messages) => (messages.admin as Record<string, string>)), | ||
locale: params.locale as string, | ||
}); | ||
|
||
|
||
return ( | ||
<NextAdmin | ||
{...props} | ||
locale={params.locale as string} | ||
dashboard={Dashboard} | ||
/> | ||
); | ||
} |
6 changes: 3 additions & 3 deletions
6
apps/example/app/admin/custom/page.tsx → ...xample/app/[locale]/admin/custom/page.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { PropsWithChildren } from "react"; | ||
import "../../styles.css"; | ||
import { notFound } from "next/navigation"; | ||
|
||
type Props = { | ||
params: { | ||
locale: "en" | "fr"; | ||
}; | ||
}; | ||
|
||
const locales = ["en", "fr"]; | ||
|
||
export default function Layout({ | ||
children, | ||
params: { locale }, | ||
}: PropsWithChildren<Props>) { | ||
if (!locales.includes(locale)) { | ||
notFound(); | ||
} | ||
|
||
return ( | ||
<html lang={locale}> | ||
<body>{children}</body> | ||
</html> | ||
); | ||
} |
File renamed without changes.
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { IntlErrorCode } from "next-intl"; | ||
import { getRequestConfig } from "next-intl/server"; | ||
|
||
export default getRequestConfig(async ({ locale }) => ({ | ||
messages: (await import(`./messages/${locale}.json`)).default, | ||
getMessageFallback: ({ namespace, key, error }) => { | ||
const path = [namespace, key].filter((part) => part != null).join("."); | ||
|
||
if (error.code === IntlErrorCode.MISSING_MESSAGE) { | ||
return ""; | ||
} else { | ||
return "Dear developer, please fix this message: " + path; | ||
} | ||
}, | ||
})); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
{ | ||
"admin": { | ||
"actions": { | ||
"user": { | ||
"email": { | ||
"title": "Send email", | ||
"success": "Email sent successfully", | ||
"error": "Error while sending email" | ||
} | ||
} | ||
}, | ||
"form": { | ||
"user": { | ||
"email": { | ||
"error": "Invalid email" | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
{ | ||
"admin": { | ||
"list": { | ||
"header": { | ||
"add": { | ||
"label": "Ajouter" | ||
}, | ||
"search": { | ||
"placeholder": "Recherche" | ||
} | ||
}, | ||
"footer": { | ||
"indicator": { | ||
"showing": "Affichage de", | ||
"to": "à", | ||
"of": "sur" | ||
} | ||
}, | ||
"row": { | ||
"actions": { | ||
"delete": { | ||
"label": "Supprimer" | ||
} | ||
} | ||
}, | ||
"empty": { | ||
"label": "Aucun(e) {{resource}} trouvée" | ||
} | ||
}, | ||
"form": { | ||
"button": { | ||
"delete": { | ||
"label": "Supprimer" | ||
}, | ||
"save": { | ||
"label": "Enregistrer" | ||
} | ||
}, | ||
"widgets": { | ||
"file_upload": { | ||
"label": "Choisir un fichier", | ||
"delete": "Supprimer" | ||
} | ||
}, | ||
"user": { | ||
"email": { | ||
"error": "Email invalide" | ||
} | ||
} | ||
}, | ||
"actions": { | ||
"user": { | ||
"email": { | ||
"title": "Envoyer un email", | ||
"success": "Email envoyé avec succès", | ||
"error": "Erreur lors de l'envoi de l'email" | ||
} | ||
}, | ||
"label": "Action", | ||
"delete": { | ||
"label": "Supprimer" | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import createMiddleware from "next-intl/middleware"; | ||
|
||
export default createMiddleware({ | ||
locales: ["en", "fr"], | ||
defaultLocale: "en", | ||
localeDetection: false, | ||
localePrefix: "always", | ||
alternateLinks: false, | ||
}); | ||
|
||
export const config = { | ||
matcher: [ | ||
"/", | ||
"/(fr|en)/:path*", | ||
"/((?!_next|_vercel|pagerouter|api|.*\\..*).*)", | ||
], | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.