diff --git a/src/common/utils/locale-path.ts b/src/common/utils/locale-path.ts index 213eb9ca..7945bdd6 100644 --- a/src/common/utils/locale-path.ts +++ b/src/common/utils/locale-path.ts @@ -20,16 +20,22 @@ type RetrievablePath = function getPathWithDelimiter(delimiter: Delimiter, segments: string[] = []): RetrievablePath { const recursiveHandler = { - get(target: Shape, prop: string): unknown { + get(target: Shape, prop: string | symbol): unknown { switch (prop) { - case '__path__': { + case '__path__': + { return segments.join(delimiter) } - case 'toString': { + + case Symbol.toStringTag: + case 'toString': + case 'valueOf': + { return () => segments.join(delimiter) } + default: { - return getPathWithDelimiter(delimiter, [...segments, prop]) + return getPathWithDelimiter(delimiter, [...segments, prop as string]) } } }, diff --git a/src/common/utils/locales.ts b/src/common/utils/locales.ts index bd8c630f..080ca734 100644 --- a/src/common/utils/locales.ts +++ b/src/common/utils/locales.ts @@ -6,6 +6,9 @@ import type { Mail } from '~/def/mail' export const root = getPath()() +export const title = root.title +export const server = root.server + const _role = root.role const _scope = root.scope const _mode = root.mode diff --git a/src/components/app/footer.vue b/src/components/app/footer.vue index 8ce886db..93508c11 100644 --- a/src/components/app/footer.vue +++ b/src/components/app/footer.vue @@ -36,7 +36,7 @@ const { iconLinks, footerLink, brand } = runtime.public as unknown as { iconLink
- © {{ fullYear }} ppy.sb. All Rights Reserved. + © {{ fullYear }} ppy.sb. All Rights Reserved.
diff --git a/src/components/app/nav/index.vue b/src/components/app/nav/index.vue index 05ab5cc6..ada24646 100644 --- a/src/components/app/nav/index.vue +++ b/src/components/app/nav/index.vue @@ -99,7 +99,7 @@ function clearFocus() { }" @click="clearFocus" > - {{ t('titles.settings') }} + {{ t('title.settings') }}
  • @@ -109,7 +109,7 @@ function clearFocus() { }" @click="clearFocus" > - {{ t('titles.relations') }} + {{ t('title.relations') }}
  • @@ -122,7 +122,7 @@ function clearFocus() { }" @click="clearFocus" > - {{ t('titles.userpage') }} + {{ t('title.userpage') }}
  • @@ -132,7 +132,7 @@ function clearFocus() { }" @click="clearFocus" > - {{ t('titles.admin-panel') }} + {{ t('title.admin-panel') }}
  • diff --git a/src/components/app/nav/items.vue b/src/components/app/nav/items.vue index 4cd695f6..30f4b362 100644 --- a/src/components/app/nav/items.vue +++ b/src/components/app/nav/items.vue @@ -18,19 +18,19 @@ function clearFocus() {
  • - {{ t('titles.leaderboard') }} + {{ t('title.leaderboard') }}
  • - [{{ t('global.wip') }}] {{ t('titles.clans') }} + [{{ t('global.wip') }}] {{ t('title.clans') }}
  • - {{ t('titles.status') }} + {{ t('title.status') }}
  • diff --git a/src/composables/useSearchablePages.tsx b/src/composables/useSearchablePages.tsx index 12ef34ad..3bb9cbc9 100644 --- a/src/composables/useSearchablePages.tsx +++ b/src/composables/useSearchablePages.tsx @@ -60,7 +60,7 @@ export const pages: { class="w-5 h-5" size="100%" /> - {useI18n({ useScope: 'global' }).t('titles.admin-panel')} + {useI18n({ useScope: 'global' }).t('title.admin-panel')} ), route: () => ({ @@ -81,7 +81,7 @@ export const pages: { render: () => ( <> - {useI18n({ useScope: 'global' }).t('titles.relations')} + {useI18n({ useScope: 'global' }).t('title.relations')} ), route: () => ({ @@ -94,7 +94,7 @@ export const pages: { render: () => ( <> - {useI18n({ useScope: 'global' }).t('titles.settings')} + {useI18n({ useScope: 'global' }).t('title.settings')} ), route: () => ({ diff --git a/src/locales/@types.d.ts b/src/locales/@types.d.ts index fc922bfd..a7fa72e3 100644 --- a/src/locales/@types.d.ts +++ b/src/locales/@types.d.ts @@ -8,13 +8,14 @@ import type { Scope, UserRole } from '~/def/user' import { Lang, type Rank } from '~/def' import type { ActiveMode, ActiveRuleset } from '~/def/common' -type Titles = +type Title = | 'leaderboard' | 'status' | 'settings' | 'relations' | 'userpage' | 'admin-panel' +| 'user-management' | 'logs' | 'articles' | 'clans' @@ -60,8 +61,8 @@ export interface GlobalI18n extends PathAccessibleObject { } role: Record scope: Record - titles: Record< - Titles, + title: Record< + Title, string > global: Record diff --git a/src/locales/base/en-GB.ts b/src/locales/base/en-GB.ts index 2700ac69..3be14575 100644 --- a/src/locales/base/en-GB.ts +++ b/src/locales/base/en-GB.ts @@ -10,6 +10,7 @@ export default { server: { name: 'Guccho', }, + footer: { about: 'About', resources: 'Resources', @@ -33,7 +34,8 @@ export default { [Rank.TotalScore]: 'Total Score', [Rank.Score]: 'Score', }, - titles: { + + title: { 'leaderboard': 'Leaderboard', 'status': 'Status', 'settings': 'Settings', @@ -44,6 +46,7 @@ export default { 'articles': 'Articles', 'clans': 'Clans', 'account-recovery': 'Account Recovery', + 'user-management': 'User Management', }, global: { 'logout': 'Sign out', diff --git a/src/locales/base/fr-FR.ts b/src/locales/base/fr-FR.ts index 9f821ead..5a345d7b 100644 --- a/src/locales/base/fr-FR.ts +++ b/src/locales/base/fr-FR.ts @@ -1,13 +1,15 @@ import type { GlobalI18n } from '../@types' -import enGB from './en-GB' import { CountryCode } from '~/def/country-code' import { Rank } from '~/def' import { Scope, UserRole } from '~/def/user' export default { -// intentionally omit 'server' to fallback to enGB - mode: enGB.mode, - ruleset: enGB.ruleset, + // reuse en-GB + server: {} as any, + footer: {} as any, + + mode: {} as any, + ruleset: {} as any, rank: { [Rank.PPv2]: 'Performance(v2)', [Rank.PPv1]: 'Performance(v1)', @@ -15,7 +17,7 @@ export default { [Rank.TotalScore]: 'Score Total', [Rank.Score]: 'Score', }, - titles: { + title: { 'leaderboard': 'Classement', 'status': 'Statut', 'settings': 'Paramètres', @@ -25,7 +27,11 @@ export default { 'logs': 'Logs', 'articles': 'Articles', 'clans': 'Clans', + 'user-management': 'Gestion d\'utilisateur', + // TODO refine fr translation + 'account-recovery': 'Account Recovery', }, + global: { 'logout': 'Déconnexion', 'login': 'Connexion', @@ -43,9 +49,11 @@ export default { 'users': 'Utilisateur', 'session': 'Session', 'password': 'Mot de passe', + // TODO refine fr translation 'email': 'Email', 'otp': 'One time code', 'verify': 'Verify', + 'wip': 'WIP', }, role: { [UserRole.Disabled]: 'Désactivé', @@ -65,6 +73,7 @@ export default { [UserRole.Owner]: 'Propriétaire', [UserRole.Bot]: 'Bot', }, + scope: { [Scope.Self]: 'Moi', [Scope.Friends]: 'Amis', @@ -75,6 +84,10 @@ export default { ranks: 'Classement', sessions: 'Connexion Web', }, + + beatmap: {} as any, + + error: {} as any, country: { [CountryCode.Unknown]: 'Inconnu', [CountryCode.Afghanistan]: 'Afghanistan', @@ -327,4 +340,5 @@ export default { [CountryCode.Zambia]: 'Zambie', [CountryCode.Zimbabwe]: 'Zimbabwe', }, -} satisfies Omit + mail: {} as any, +} satisfies GlobalI18n diff --git a/src/locales/base/zh-CN.ts b/src/locales/base/zh-CN.ts index 05cc9d4c..52373e68 100644 --- a/src/locales/base/zh-CN.ts +++ b/src/locales/base/zh-CN.ts @@ -9,13 +9,12 @@ import { GucchoError } from '~/def/messages' export default { // reuse en-GB server: {} as any, - mode: {} as any, - ruleset: {} as any, - footer: { about: '关于', resources: '资源', }, + mode: {} as any, + ruleset: {} as any, rank: { [Rank.PPv2]: 'Performance(v2)', @@ -25,7 +24,7 @@ export default { [Rank.Score]: '分数', }, - titles: { + title: { 'leaderboard': '排行榜', 'status': '状态', 'settings': '设置', @@ -36,6 +35,7 @@ export default { 'articles': '文章', 'clans': '家人们', 'account-recovery': '找回账号', + 'user-management': '用户管理', }, global: { diff --git a/src/pages/admin/index.vue b/src/pages/admin/index.vue index 77375322..0d7ec281 100644 --- a/src/pages/admin/index.vue +++ b/src/pages/admin/index.vue @@ -1,16 +1,11 @@ - - -en-GB: - user-management: User Management -zh-CN: - user-management: 用户管理 -fr-FR: - user-management: Gestion d'utilisateur - - - - diff --git a/src/pages/admin/logs.vue b/src/pages/admin/logs.vue index dba0cf50..10efd632 100644 --- a/src/pages/admin/logs.vue +++ b/src/pages/admin/logs.vue @@ -3,6 +3,12 @@ const app = useNuxtApp() const last = ref(50) const { data: logs } = await app.$client.admin.log.last.useQuery(last) const { t, locale } = useI18n() + +useHead({ + title: () => t(localeKey.title.logs.__path__), + titleTemplate: title => `${title} - ${t(localeKey.server.name.__path__)}`, +}) + async function truncate() { logs.value = await app.$client.admin.log.truncate.mutate() } @@ -12,7 +18,7 @@ async function truncate() {

    - {{ t('titles.logs') }} + {{ t('title.logs') }}