feat(i18n): implement internationalization support and refactor components for localization

- Added i18n configuration to `astro.config.mjs` for managing locales.
- Introduced utility functions for locale handling in `i18n.ts`.
- Updated various components (e.g., `BackButton`, `Button`, `Community`, `Footer`, `Hero`, `NavBar`, etc.) to utilize localized strings.
- Created new localized pages for `about`, `donate`, `download`, `release-notes`, and others.
- Removed outdated pages and adjusted imports to reflect new structure.
- Enhanced the `ModsList` component to support localization.
- Added English language JSON file for translations.
- Improved overall code organization and structure for better maintainability.
This commit is contained in:
taroj1205 2025-05-09 23:49:41 +12:00
parent 904d921c09
commit 54dfef1eac
No known key found for this signature in database
GPG key ID: 0FCB6CFFE0981AB7
36 changed files with 1481 additions and 844 deletions

View file

@ -1,8 +1,9 @@
import { useState, useEffect } from 'preact/hooks'
import type { ZenTheme } from '../mods'
import type { ZenTheme } from '@/mods'
import { library, icon } from '@fortawesome/fontawesome-svg-core'
import { faSort, faSortUp, faSortDown } from '@fortawesome/free-solid-svg-icons'
import { useModsSearch } from '../hooks/useModsSearch'
import { useModsSearch } from '@/hooks/useModsSearch'
import { getUI, type Locale } from '@/utils/i18n'
// Add icons to the library
library.add(faSort, faSortUp, faSortDown)
@ -13,10 +14,11 @@ const ascSortIcon = icon({ prefix: 'fas', iconName: 'sort-up' })
const descSortIcon = icon({ prefix: 'fas', iconName: 'sort-down' })
interface ModsListProps {
mods: ZenTheme[]
allMods: ZenTheme[]
locale: Locale
}
export default function ModsList({ mods }: ModsListProps) {
export default function ModsList({ allMods, locale }: ModsListProps) {
const {
search,
createdSort,
@ -32,7 +34,7 @@ export default function ModsList({ mods }: ModsListProps) {
setLimit,
mods: paginatedMods,
searchParams,
} = useModsSearch(mods)
} = useModsSearch(allMods)
const [pageInput, setPageInput] = useState(page.toString())
@ -78,6 +80,8 @@ export default function ModsList({ mods }: ModsListProps) {
window.scrollTo(0, 0)
}
const { routes: { mods } } = getUI(locale)
function renderPagination() {
if (totalPages <= 1) return null
return (
@ -94,17 +98,26 @@ export default function ModsList({ mods }: ModsListProps) {
&lt;
</button>
<form onSubmit={handlePageSubmit} className="flex items-center gap-2">
<span className="text-sm">Page</span>
<input
type="text"
value={pageInput}
onInput={handlePageInputChange}
className="w-16 rounded border border-dark bg-transparent px-2 py-1 text-center text-sm"
aria-label="Page number"
/>
<span className="text-sm">
of {totalPages} ({totalItems} items)
</span>
{
mods.pagination.pagination.split('{input}').map((value, index) => {
if (index === 0) {
return (
<input
type="text"
value={pageInput}
onInput={handlePageInputChange}
className="w-16 rounded border border-dark bg-transparent px-2 py-1 text-center text-sm"
aria-label="Page number"
/>
)
}
return (
<span className="text-sm">
{value.replace('{totalPages}', totalPages.toString()).replace('{totalItems}', totalItems.toString())}
</span>
)
})
}
</form>
<button
type="button"
@ -129,7 +142,7 @@ export default function ModsList({ mods }: ModsListProps) {
type="text"
id="search"
className="w-full rounded-full border-2 border-dark bg-transparent px-6 py-2 text-lg outline-none"
placeholder="Type to search..."
placeholder={mods.search}
value={search}
onInput={handleSearch}
/>
@ -142,7 +155,7 @@ export default function ModsList({ mods }: ModsListProps) {
onClick={toggleCreatedSort}
className="text-md flex items-center gap-2 px-4 py-2 font-semibold"
>
Last created
{mods.sort.lastCreated}
<span
dangerouslySetInnerHTML={{
__html: getSortIcon(createdSort).html[0],
@ -157,7 +170,7 @@ export default function ModsList({ mods }: ModsListProps) {
onClick={toggleUpdatedSort}
className="text-md flex items-center gap-2 px-4 py-2 font-semibold"
>
Last updated
{mods.sort.lastUpdated}
<span
dangerouslySetInnerHTML={{
__html: getSortIcon(updatedSort).html[0],
@ -168,7 +181,7 @@ export default function ModsList({ mods }: ModsListProps) {
<div className="flex items-center gap-2 px-4 py-2">
<label htmlFor="limit" className="text-md font-semibold">
Per page:
{mods.sort.perPage}
</label>
<select
id="limit"
@ -214,9 +227,9 @@ export default function ModsList({ mods }: ModsListProps) {
))
) : (
<div className="col-span-4 grid place-items-center gap-4 place-self-center px-8 text-center">
<h2 className="text-lg font-bold">No results found</h2>
<h2 className="text-lg font-bold">{mods.noResults}</h2>
<p className="text-sm font-thin">
Try searching for a different term or check back later.
{mods.noResultsDescription}
</p>
</div>
)}