Foro multiidioma: nombres/descripciones de categorías y foros (ES/EN)
forum_categories.name_en y forums.name_en/description_en (sql/add_forum_en.sql, aplicado en prod y traducidos los existentes: Comunidad/Anuncios/Discusión general). getForumIndex(locale) y getForum(id, locale) usan EN si existe, si no caen al español. Las páginas del foro pasan el locale. Labels (Temas/Mensajes) ya estaban traducidos. Verificado: /en/forum en inglés, /es/forum en español. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -23,7 +23,7 @@ export default async function ForumPage({
|
|||||||
const t = await getTranslations('Forum')
|
const t = await getTranslations('Forum')
|
||||||
|
|
||||||
const id = Number(forumId)
|
const id = Number(forumId)
|
||||||
const forum = await getForum(id)
|
const forum = await getForum(id, locale)
|
||||||
if (!forum) notFound()
|
if (!forum) notFound()
|
||||||
const total = await countTopics(id)
|
const total = await countTopics(id)
|
||||||
const totalPages = Math.max(1, Math.ceil(total / PER_PAGE))
|
const totalPages = Math.max(1, Math.ceil(total / PER_PAGE))
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export default async function ForumIndexPage({ params }: { params: Promise<{ loc
|
|||||||
const { locale } = await params
|
const { locale } = await params
|
||||||
setRequestLocale(locale)
|
setRequestLocale(locale)
|
||||||
const t = await getTranslations('Forum')
|
const t = await getTranslations('Forum')
|
||||||
const categories = await getForumIndex()
|
const categories = await getForumIndex(locale)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageShell title={t('title')}>
|
<PageShell title={t('title')}>
|
||||||
|
|||||||
+16
-8
@@ -60,13 +60,14 @@ export interface SearchResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Índice del foro: categorías con sus foros visibles (+ contadores y último tema). */
|
/** Índice del foro: categorías con sus foros visibles (+ contadores y último tema). */
|
||||||
export async function getForumIndex(): Promise<Category[]> {
|
export async function getForumIndex(locale = 'es'): Promise<Category[]> {
|
||||||
|
const en = locale === 'en'
|
||||||
try {
|
try {
|
||||||
const [cats] = await db(DB.web).query<RowDataPacket[]>(
|
const [cats] = await db(DB.web).query<RowDataPacket[]>(
|
||||||
'SELECT id, name FROM forum_categories ORDER BY `order`, id',
|
'SELECT id, name, name_en FROM forum_categories ORDER BY `order`, id',
|
||||||
)
|
)
|
||||||
const [forums] = await db(DB.web).query<RowDataPacket[]>(
|
const [forums] = await db(DB.web).query<RowDataPacket[]>(
|
||||||
`SELECT f.id, f.category_id, f.name, f.description, f.icon,
|
`SELECT f.id, f.category_id, f.name, f.name_en, f.description, f.description_en, f.icon,
|
||||||
(SELECT COUNT(*) FROM forum_topics t WHERE t.forum_id = f.id AND t.deleted = 0) AS topic_count,
|
(SELECT COUNT(*) FROM forum_topics t WHERE t.forum_id = f.id AND t.deleted = 0) AS topic_count,
|
||||||
(SELECT COUNT(*) FROM forum_posts p JOIN forum_topics t ON p.topic_id = t.id
|
(SELECT COUNT(*) FROM forum_posts p JOIN forum_topics t ON p.topic_id = t.id
|
||||||
WHERE t.forum_id = f.id AND p.deleted = 0 AND t.deleted = 0) AS post_count,
|
WHERE t.forum_id = f.id AND p.deleted = 0 AND t.deleted = 0) AS post_count,
|
||||||
@@ -82,12 +83,14 @@ export async function getForumIndex(): Promise<Category[]> {
|
|||||||
)
|
)
|
||||||
const byCat = new Map<number, ForumInfo[]>()
|
const byCat = new Map<number, ForumInfo[]>()
|
||||||
for (const f of forums) {
|
for (const f of forums) {
|
||||||
const info = f as unknown as ForumInfo
|
const info = f as unknown as ForumInfo & { name_en?: string | null; description_en?: string | null }
|
||||||
|
info.name = en && info.name_en ? info.name_en : info.name
|
||||||
|
info.description = en && info.description_en ? info.description_en : info.description
|
||||||
if (!byCat.has(info.category_id)) byCat.set(info.category_id, [])
|
if (!byCat.has(info.category_id)) byCat.set(info.category_id, [])
|
||||||
byCat.get(info.category_id)!.push(info)
|
byCat.get(info.category_id)!.push(info)
|
||||||
}
|
}
|
||||||
return cats
|
return cats
|
||||||
.map((c) => ({ id: c.id, name: c.name, forums: byCat.get(c.id) ?? [] }))
|
.map((c) => ({ id: c.id, name: en && c.name_en ? c.name_en : c.name, forums: byCat.get(c.id) ?? [] }))
|
||||||
.filter((c) => c.forums.length > 0)
|
.filter((c) => c.forums.length > 0)
|
||||||
} catch {
|
} catch {
|
||||||
return []
|
return []
|
||||||
@@ -106,13 +109,18 @@ export async function listForumsForMove(): Promise<{ id: number; name: string }[
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getForum(id: number): Promise<{ name: string; description: string } | null> {
|
export async function getForum(id: number, locale = 'es'): Promise<{ name: string; description: string } | null> {
|
||||||
|
const en = locale === 'en'
|
||||||
try {
|
try {
|
||||||
const [rows] = await db(DB.web).query<RowDataPacket[]>(
|
const [rows] = await db(DB.web).query<RowDataPacket[]>(
|
||||||
'SELECT name, description FROM forums WHERE id = ? AND visibility = 1 AND deleted = 0',
|
'SELECT name, name_en, description, description_en FROM forums WHERE id = ? AND visibility = 1 AND deleted = 0',
|
||||||
[id],
|
[id],
|
||||||
)
|
)
|
||||||
return rows[0] ? { name: rows[0].name, description: rows[0].description } : null
|
if (!rows[0]) return null
|
||||||
|
return {
|
||||||
|
name: en && rows[0].name_en ? rows[0].name_en : rows[0].name,
|
||||||
|
description: en && rows[0].description_en ? rows[0].description_en : rows[0].description,
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
-- Foro multiidioma: nombre/descripción en inglés (opcional). Si están vacíos, se
|
||||||
|
-- cae a la versión en español. El texto original es ES.
|
||||||
|
ALTER TABLE forum_categories ADD COLUMN name_en VARCHAR(255) NULL AFTER name;
|
||||||
|
ALTER TABLE forums
|
||||||
|
ADD COLUMN name_en VARCHAR(45) NULL AFTER name,
|
||||||
|
ADD COLUMN description_en TEXT NULL AFTER description;
|
||||||
|
|
||||||
|
-- Traducción de las categorías/foros existentes.
|
||||||
|
UPDATE forum_categories SET name_en = 'Community' WHERE name = 'Comunidad';
|
||||||
|
UPDATE forums SET name_en = 'Announcements',
|
||||||
|
description_en = 'Official server news and announcements.' WHERE name = 'Anuncios';
|
||||||
|
UPDATE forums SET name_en = 'General Discussion',
|
||||||
|
description_en = 'Talk about everything server-related with the community.' WHERE name = 'Discusión general';
|
||||||
Reference in New Issue
Block a user