wip: ESLint Rule against loss of reactivity + prep for string-only locale files
This commit is contained in:
parent
d2020cafec
commit
3c26238ca4
7 changed files with 251 additions and 223 deletions
|
|
@ -47,6 +47,7 @@ export default defineConfig([
|
|||
"error",
|
||||
{ allowInterfaces: "with-single-extends" },
|
||||
],
|
||||
"vue/no-ref-object-reactivity-loss": ["error"],
|
||||
},
|
||||
},
|
||||
// disable multi-word-component-names for unplugin-vue-router
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import type { DeepRemoveFallback, Fallback, MessagePack } from "./marker";
|
||||
import type { DeepRemoveFallback } from "./marker";
|
||||
import type { RichTemplate } from "./rich";
|
||||
import type { VilanticId } from "./vilantic";
|
||||
|
||||
export interface Locale extends DeepRemoveFallback<LocaleMask> {}
|
||||
|
||||
export type LocaleMask = MessagePack<{
|
||||
export type LocaleMask = {
|
||||
localeName: string;
|
||||
vilanticLangs: VilanticLangs;
|
||||
navbar: Navbar;
|
||||
|
|
@ -12,91 +12,81 @@ export type LocaleMask = MessagePack<{
|
|||
resources: ResourcesPage;
|
||||
kotoba: KotobaPage;
|
||||
discord: Discord;
|
||||
}>;
|
||||
};
|
||||
|
||||
export type VilanticLangs = MessagePack<Record<VilanticId, string>>;
|
||||
export type VilanticLangs = Record<VilanticId, string>;
|
||||
|
||||
export type Navbar = MessagePack<
|
||||
Record<"whatIsViossa" | "resources" | "kotoba", string>
|
||||
export type Navbar = Record<"whatIsViossa" | "resources" | "kotoba", string>;
|
||||
|
||||
export type HomePage = {
|
||||
sections: HomeSections;
|
||||
images: Record<"viossaFlag", Image>;
|
||||
};
|
||||
|
||||
export type HomeSections = Record<
|
||||
"whatIsViossa" | "historyOfViossa" | "community",
|
||||
HomeSection
|
||||
>;
|
||||
|
||||
export type HomePage = MessagePack<{ sections: HomeSections }>;
|
||||
export type HomeSection = { title: string; body: string };
|
||||
|
||||
export type HomeSections = MessagePack<
|
||||
Record<"whatIsViossa" | "historyOfViossa" | "community", HomeSection>
|
||||
>;
|
||||
|
||||
export type HomeSection = MessagePack<{
|
||||
title: string;
|
||||
text: string;
|
||||
image: Image | null;
|
||||
}>;
|
||||
|
||||
export type ResourcesPage = MessagePack<{
|
||||
export type ResourcesPage = {
|
||||
title: string;
|
||||
resources: Resources;
|
||||
}>;
|
||||
images: Record<"discordLogo", Image>;
|
||||
};
|
||||
|
||||
export type Resources = MessagePack<{ discord: Resource<"join" | "rules"> }>;
|
||||
export type Resources = { discord: Resource<"join" | "rules"> };
|
||||
|
||||
export type Resource<ButtonKey extends string> = MessagePack<{
|
||||
export type Resource<ButtonKey extends string> = {
|
||||
title: string;
|
||||
subtitle: string;
|
||||
desc: string;
|
||||
image: Image | null;
|
||||
buttons: MessagePack<Record<ButtonKey, Button>>;
|
||||
}>;
|
||||
buttons: Record<ButtonKey, Button>;
|
||||
};
|
||||
|
||||
export type KotobaPage = MessagePack<{ title: string; searchHelp: string }>;
|
||||
export type KotobaPage = { title: string; searchHelp: string };
|
||||
|
||||
export type Button = MessagePack<{ label: string }>;
|
||||
export type Button = { label: string };
|
||||
|
||||
// coupled to require alt text for all images
|
||||
export type Image = MessagePack<{
|
||||
src: string | Fallback; // fallback can be used if image doesn't need to be translated
|
||||
alt: string;
|
||||
}>;
|
||||
export type Image = { alt: string };
|
||||
|
||||
export type Discord = MessagePack<{ rulesPage: DiscordRulesPage }>;
|
||||
export type Discord = { rulesPage: DiscordRulesPage };
|
||||
|
||||
export type DiscordRulesPage = MessagePack<{
|
||||
export type DiscordRulesPage = {
|
||||
title: string;
|
||||
overview: DiscordRulesPageOverview;
|
||||
rules: DiscordRules;
|
||||
}>;
|
||||
};
|
||||
|
||||
export type DiscordRulesPageOverview = MessagePack<{
|
||||
title: string;
|
||||
help: string;
|
||||
}>;
|
||||
export type DiscordRulesPageOverview = { title: string; help: string };
|
||||
|
||||
export type DiscordRules = MessagePack<
|
||||
Record<
|
||||
| "noTranslation"
|
||||
| "lfsv"
|
||||
| "viossaOnlyChats"
|
||||
| "sfw"
|
||||
| "respectOthers"
|
||||
| "respectStaff"
|
||||
| "controversialTopics",
|
||||
DiscordRule
|
||||
>
|
||||
export type DiscordRules = Record<
|
||||
| "noTranslation"
|
||||
| "lfsv"
|
||||
| "viossaOnlyChats"
|
||||
| "sfw"
|
||||
| "respectOthers"
|
||||
| "respectStaff"
|
||||
| "controversialTopics",
|
||||
DiscordRule
|
||||
>;
|
||||
|
||||
export type DiscordRule = MessagePack<{
|
||||
export type DiscordRule = {
|
||||
overview: DiscordRuleOverview;
|
||||
section: DiscordRuleSection;
|
||||
}>;
|
||||
};
|
||||
|
||||
export type DiscordRuleOverview = MessagePack<{
|
||||
export type DiscordRuleOverview = {
|
||||
text: RichTemplate<never>;
|
||||
subtext: RichTemplate<never> | null;
|
||||
}>;
|
||||
};
|
||||
|
||||
export type DiscordRuleSection = MessagePack<{
|
||||
export type DiscordRuleSection = {
|
||||
header: (ctx: { ruleNumber: number }) => string;
|
||||
body: DiscordRuleSectionBodyElement[];
|
||||
}>;
|
||||
};
|
||||
|
||||
export type DiscordRuleSectionBodyElement =
|
||||
| { type: "paragraph"; paragraph: RichTemplate<never> }
|
||||
|
|
|
|||
|
|
@ -1,78 +1,65 @@
|
|||
import { type Locale } from "@/i18n/locale";
|
||||
import flakkaImg from "@/assets/flakka.png";
|
||||
import discordImg from "@/assets/discord.png";
|
||||
import { boldT, italicT, linkT, richT } from "@/i18n/rich";
|
||||
import { messagePack, type DeepStrictMessagePackValues } from "@/i18n/marker";
|
||||
import { type DeepStrictMessagePackValues } from "@/i18n/marker";
|
||||
|
||||
export default messagePack({
|
||||
export default {
|
||||
localeName: "English",
|
||||
vilanticLangs: messagePack({ viossa: "Viossa", wodox: "Wodoch" }),
|
||||
navbar: messagePack({
|
||||
vilanticLangs: { viossa: "Viossa", wodox: "Wodoch" },
|
||||
navbar: {
|
||||
whatIsViossa: "What is Viossa?",
|
||||
resources: "Resources",
|
||||
kotoba: "Kotoba",
|
||||
}),
|
||||
home: messagePack({
|
||||
sections: messagePack({
|
||||
whatIsViossa: messagePack({
|
||||
},
|
||||
home: {
|
||||
sections: {
|
||||
whatIsViossa: {
|
||||
title: "What is Viossa?",
|
||||
text: "Viossa is a community-created artificial pidgin language, created to simulate the formation of natural pidgin languages. Viossa is characterized by its lack of standardization, with each speaker developing a personal idiolect. Spelling and pronunciation can vary greatly, and serve as a form of personal self-expression. Viossa is learnt and taught entirely by immersion — translation is prohibited while learning.",
|
||||
image: messagePack({
|
||||
src: flakkaImg,
|
||||
alt: "Flag of the Viossa Language",
|
||||
}),
|
||||
}),
|
||||
historyOfViossa: messagePack({
|
||||
body: "Viossa is a community-created artificial pidgin language, created to simulate the formation of natural pidgin languages. Viossa is characterized by its lack of standardization, with each speaker developing a personal idiolect. Spelling and pronunciation can vary greatly, and serve as a form of personal self-expression. Viossa is learnt and taught entirely by immersion — translation is prohibited while learning.",
|
||||
},
|
||||
historyOfViossa: {
|
||||
title: "History of Viossa",
|
||||
text: "Viossa began as a Skype group in 2014, created by members of the r/conlangs community on Reddit, as an experiment to simulate the formation of a pidgin language. Pidgins are simplified languages resulting from contact between populations with no shared common language. Unlike most pidgins, which usually have two to three contributor languages, Viossa comes from many diverse languages. This is because people from all around the world helped to contribute to Viossa's vocabulary.",
|
||||
image: messagePack({
|
||||
src: flakkaImg,
|
||||
alt: "Flag of the Viossa Language",
|
||||
}),
|
||||
}),
|
||||
community: messagePack({
|
||||
body: "Viossa began as a Skype group in 2014, created by members of the r/conlangs community on Reddit, as an experiment to simulate the formation of a pidgin language. Pidgins are simplified languages resulting from contact between populations with no shared common language. Unlike most pidgins, which usually have two to three contributor languages, Viossa comes from many diverse languages. This is because people from all around the world helped to contribute to Viossa's vocabulary.",
|
||||
},
|
||||
community: {
|
||||
title: "Community",
|
||||
text: "The Viossa community is rich and colourful, drawing from many global traditions due to its worldwide online membership. Since the teaching culture puts an emphasis on linguistic immersion, and discourages prescriptivism, the culture of Viossa is as diverse and varied as the language and the people who speak it. For many, their personal dialect is a key form of identity and expression. The fluid nature of Viossa and lack of defined meanings makes Viossa popular for creative purposes, such as poetry and songwriting.",
|
||||
image: null,
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
resources: messagePack({
|
||||
body: "The Viossa community is rich and colourful, drawing from many global traditions due to its worldwide online membership. Since the teaching culture puts an emphasis on linguistic immersion, and discourages prescriptivism, the culture of Viossa is as diverse and varied as the language and the people who speak it. For many, their personal dialect is a key form of identity and expression. The fluid nature of Viossa and lack of defined meanings makes Viossa popular for creative purposes, such as poetry and songwriting.",
|
||||
},
|
||||
},
|
||||
images: { viossaFlag: { alt: "Flag of the Viossa Language" } },
|
||||
},
|
||||
resources: {
|
||||
title: "Learning Resources",
|
||||
resources: messagePack({
|
||||
discord: messagePack({
|
||||
resources: {
|
||||
discord: {
|
||||
title: "Discord Server",
|
||||
subtitle:
|
||||
"This is where most of the action happens! Hop on in!",
|
||||
desc: "Originally started in 2015 something something read the rules here, then click the link below to join!",
|
||||
image: messagePack({ src: discordImg, alt: "Discord logo" }),
|
||||
buttons: messagePack({
|
||||
join: messagePack({ label: "Join" }),
|
||||
rules: messagePack({ label: "Rules" }),
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
kotoba: messagePack({
|
||||
buttons: { join: { label: "Join" }, rules: { label: "Rules" } },
|
||||
},
|
||||
},
|
||||
images: { discordLogo: { alt: "Discord logo" } },
|
||||
},
|
||||
kotoba: {
|
||||
title: "Tropos-agnostic search",
|
||||
searchHelp: "To searcn tropos-agnostically, enter a term below.",
|
||||
}),
|
||||
discord: messagePack({
|
||||
rulesPage: messagePack({
|
||||
},
|
||||
discord: {
|
||||
rulesPage: {
|
||||
title: "Discord Server Rules",
|
||||
overview: messagePack({
|
||||
overview: {
|
||||
title: "Overview",
|
||||
help: "Click any rule to see details.",
|
||||
}),
|
||||
rules: messagePack({
|
||||
noTranslation: messagePack({
|
||||
overview: messagePack({
|
||||
},
|
||||
rules: {
|
||||
noTranslation: {
|
||||
overview: {
|
||||
text: richT(
|
||||
"No translation! Do not translate to/from Viossa on the server, except the big four translatables (you can learn in hard mode without them!)",
|
||||
),
|
||||
subtext: null,
|
||||
}),
|
||||
section: messagePack({
|
||||
},
|
||||
section: {
|
||||
header: ({ ruleNumber }) =>
|
||||
`Rule ${String(ruleNumber)}: No translation`,
|
||||
body: [
|
||||
|
|
@ -107,14 +94,14 @@ export default messagePack({
|
|||
),
|
||||
},
|
||||
],
|
||||
}),
|
||||
}),
|
||||
lfsv: messagePack({
|
||||
overview: messagePack({
|
||||
},
|
||||
},
|
||||
lfsv: {
|
||||
overview: {
|
||||
text: richT("If it's understood, it's Viossa."),
|
||||
subtext: null,
|
||||
}),
|
||||
section: messagePack({
|
||||
},
|
||||
section: {
|
||||
header: ({ ruleNumber }) =>
|
||||
`Rule ${String(ruleNumber)}: If it's understood, it's Viossa`,
|
||||
body: [
|
||||
|
|
@ -131,16 +118,16 @@ export default messagePack({
|
|||
),
|
||||
},
|
||||
],
|
||||
}),
|
||||
}),
|
||||
viossaOnlyChats: messagePack({
|
||||
overview: messagePack({
|
||||
},
|
||||
},
|
||||
viossaOnlyChats: {
|
||||
overview: {
|
||||
text: richT(
|
||||
"The chats in the Viossa Only category are Viossa only.",
|
||||
),
|
||||
subtext: null,
|
||||
}),
|
||||
section: messagePack({
|
||||
},
|
||||
section: {
|
||||
header: ({ ruleNumber }) =>
|
||||
`Rule ${String(ruleNumber)}: Viossa-only chats`,
|
||||
body: [
|
||||
|
|
@ -159,16 +146,16 @@ export default messagePack({
|
|||
),
|
||||
},
|
||||
],
|
||||
}),
|
||||
}),
|
||||
sfw: messagePack({
|
||||
overview: messagePack({
|
||||
},
|
||||
},
|
||||
sfw: {
|
||||
overview: {
|
||||
text: richT(
|
||||
"This server is SFW. No sexually explicit, gory, or violent content.",
|
||||
),
|
||||
subtext: null,
|
||||
}),
|
||||
section: messagePack({
|
||||
},
|
||||
section: {
|
||||
header: ({ ruleNumber }) =>
|
||||
`Rule ${String(ruleNumber)}: SFW`,
|
||||
body: [
|
||||
|
|
@ -189,16 +176,16 @@ export default messagePack({
|
|||
),
|
||||
},
|
||||
],
|
||||
}),
|
||||
}),
|
||||
respectOthers: messagePack({
|
||||
overview: messagePack({
|
||||
},
|
||||
},
|
||||
respectOthers: {
|
||||
overview: {
|
||||
text: richT(
|
||||
"Don't use hate speech, and respect each other.",
|
||||
),
|
||||
subtext: null,
|
||||
}),
|
||||
section: messagePack({
|
||||
},
|
||||
section: {
|
||||
header: ({ ruleNumber }) =>
|
||||
`Rule ${String(ruleNumber)}: Respect one another`,
|
||||
body: [
|
||||
|
|
@ -209,10 +196,10 @@ export default messagePack({
|
|||
),
|
||||
},
|
||||
],
|
||||
}),
|
||||
}),
|
||||
respectStaff: messagePack({
|
||||
overview: messagePack({
|
||||
},
|
||||
},
|
||||
respectStaff: {
|
||||
overview: {
|
||||
text: richT(
|
||||
"Respect the rulings of the staff (",
|
||||
boldT("@Yewald"),
|
||||
|
|
@ -221,8 +208,8 @@ export default messagePack({
|
|||
").",
|
||||
),
|
||||
subtext: null,
|
||||
}),
|
||||
section: messagePack({
|
||||
},
|
||||
section: {
|
||||
header: ({ ruleNumber }) =>
|
||||
`Rule ${String(ruleNumber)}: Respect the staff's rulings`,
|
||||
body: [
|
||||
|
|
@ -245,10 +232,10 @@ export default messagePack({
|
|||
),
|
||||
},
|
||||
],
|
||||
}),
|
||||
}),
|
||||
controversialTopics: messagePack({
|
||||
overview: messagePack({
|
||||
},
|
||||
},
|
||||
controversialTopics: {
|
||||
overview: {
|
||||
text: richT(
|
||||
"Discussion of controversial topics (politics, war, etc.) should be directed to ",
|
||||
boldT("#polite"),
|
||||
|
|
@ -264,8 +251,8 @@ export default messagePack({
|
|||
boldT("#feels-and-advice"),
|
||||
" is for talking about your feelings openly, but we draw the line at suicidal or violent ideation. These are trains of thought to be brought to a therapist, and are not jokes. Because of their seriousness, they simply don't belong here.",
|
||||
),
|
||||
}),
|
||||
section: messagePack({
|
||||
},
|
||||
section: {
|
||||
header: ({ ruleNumber }) =>
|
||||
`Rule ${String(ruleNumber)}: #polite and ike`,
|
||||
body: [
|
||||
|
|
@ -344,9 +331,9 @@ export default messagePack({
|
|||
),
|
||||
},
|
||||
],
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
} as const) satisfies DeepStrictMessagePackValues<Locale>;
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as const satisfies DeepStrictMessagePackValues<Locale>;
|
||||
|
|
|
|||
|
|
@ -1,15 +1,14 @@
|
|||
import type { DeepPartialLocale } from "@/i18n";
|
||||
import { type LocaleMask } from "@/i18n/locale";
|
||||
import { messagePack } from "@/i18n/marker";
|
||||
import type { DeepPartial } from "@/utils/types";
|
||||
|
||||
export default messagePack({
|
||||
export default {
|
||||
localeName: "Viossa",
|
||||
home: messagePack({
|
||||
sections: messagePack({
|
||||
whatIsViossa: messagePack({
|
||||
home: {
|
||||
sections: {
|
||||
whatIsViossa: {
|
||||
title: "Kafaen afto Viossa",
|
||||
text: "Viossa tte glossa mahena grun vi nai vil fshtojena na bakadjin, grun vi svinnur ja! De aldjin zovti lera ne",
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
} as const) satisfies DeepPartialLocale<LocaleMask>;
|
||||
body: "Viossa tte glossa mahena grun vi nai vil fshtojena na bakadjin, grun vi svinnur ja! De aldjin zovti lera ne",
|
||||
},
|
||||
},
|
||||
},
|
||||
} as const satisfies DeepPartial<LocaleMask>;
|
||||
|
|
|
|||
|
|
@ -1,52 +1,49 @@
|
|||
import { fallback, messagePack } from "@/i18n/marker";
|
||||
import { type LocaleMask } from "@/i18n/locale";
|
||||
import type { DeepPartialLocale } from "@/i18n";
|
||||
import type { DeepPartial } from "@/utils/types";
|
||||
|
||||
export default messagePack({
|
||||
export default {
|
||||
localeName: "wodox",
|
||||
vilanticLangs: messagePack({ viossa: "viosox", wodox: "wodox" }),
|
||||
navbar: messagePack({
|
||||
vilanticLangs: { viossa: "viosox", wodox: "wodox" },
|
||||
navbar: {
|
||||
whatIsViossa: "viosox e ano?",
|
||||
resources: "tropos",
|
||||
kotoba: "mot o viosox",
|
||||
}),
|
||||
home: messagePack({
|
||||
sections: messagePack({
|
||||
whatIsViossa: messagePack({
|
||||
},
|
||||
home: {
|
||||
sections: {
|
||||
whatIsViossa: {
|
||||
title: "viosox e ano?",
|
||||
text: "viosox e hez ox pamzal, zoz stende zalkun tuo mit multa nengwi ox. zal o viosox stende lik zal o hez il ox keta, zalilkun wi tuo mit multa nengwi ox. mono i fal o viosox stendenai; omni axsi o viosox zal nengokun fal o viosox, de falmot wi falax o il stende e keko trenengwi tua o nengwi stende, ge fala e keko lik ro o tuo viosoxsi. genil viosox ibe il wi nengwi stende axkun ge pisakun po tuo ox — stende gen muskunnai mit zaiox.",
|
||||
image: messagePack({ src: fallback, alt: "fomma o viosox" }),
|
||||
}),
|
||||
historyOfViossa: messagePack({
|
||||
body: "viosox e hez ox pamzal, zoz stende zalkun tuo mit multa nengwi ox. zal o viosox stende lik zal o hez il ox keta, zalilkun wi tuo mit multa nengwi ox. mono i fal o viosox stendenai; omni axsi o viosox zal nengokun fal o viosox, de falmot wi falax o il stende e keko trenengwi tua o nengwi stende, ge fala e keko lik ro o tuo viosoxsi. genil viosox ibe il wi nengwi stende axkun ge pisakun po tuo ox — stende gen muskunnai mit zaiox.",
|
||||
},
|
||||
historyOfViossa: {
|
||||
title: "zal o viosox",
|
||||
text: "wi o zal o viosox stende po multa o Skype wi 2014 ibe stendera o multa r/conlangs o Reddit. zalsi o viosox danzalgo hez, tuo zal o viosox e lik zal o hez il ox keta, zalil tuo ox mit nengwi multa ox ibe zalsi fiemnaikun sama i ox. viosox e nengwi tuo ox pamzal keta; zalilkun keko ox keta mit lik du wi tre ox, aga zalil viosox mit multa wi plus obo o ox na il ox keta ibe zalsi o viosox stende po multa mi o mo.",
|
||||
image: messagePack({ src: fallback, alt: "fomma o viosox" }),
|
||||
}),
|
||||
community: messagePack({
|
||||
body: "wi o zal o viosox stende po multa o Skype wi 2014 ibe stendera o multa r/conlangs o Reddit. zalsi o viosox danzalgo hez, tuo zal o viosox e lik zal o hez il ox keta, zalil tuo ox mit nengwi multa ox ibe zalsi fiemnaikun sama i ox. viosox e nengwi tuo ox pamzal keta; zalilkun keko ox keta mit lik du wi tre ox, aga zalil viosox mit multa wi plus obo o ox na il ox keta ibe zalsi o viosox stende po multa mi o mo.",
|
||||
},
|
||||
community: {
|
||||
title: "viosoxsi",
|
||||
text: "nengwi multa ro o viosoxsi stende ibe stendenura po nengwi multa mi o mo ge wekakunnura zai nengwi viosoxsi po jilobo. ibe mono i fal o viosox stendenai ge ibe viosoxsi zalkun nengwi multa fal o viosox, de nengwi zoz ko o ro lik ro o viosoxsi stende po ro o viosa. po multa hez viosoxsi, falmot wi falax o tuo stende stende po ro o tuo stende. ibe mono i fal o viosox stendenai ge ibe ro o mot inkun nengwi po nengwi viosoxsi, de multa stende amanata hez, zal zalgonukun surat au mola au sucik.",
|
||||
image: null,
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
resources: messagePack({
|
||||
body: "nengwi multa ro o viosoxsi stende ibe stendenura po nengwi multa mi o mo ge wekakunnura zai nengwi viosoxsi po jilobo. ibe mono i fal o viosox stendenai ge ibe viosoxsi zalkun nengwi multa fal o viosox, de nengwi zoz ko o ro lik ro o viosoxsi stende po ro o viosa. po multa hez viosoxsi, falmot wi falax o tuo stende stende po ro o tuo stende. ibe mono i fal o viosox stendenai ge ibe ro o mot inkun nengwi po nengwi viosoxsi, de multa stende amanata hez, zal zalgonukun surat au mola au sucik.",
|
||||
},
|
||||
},
|
||||
images: { viossaFlag: { alt: "fomma o viosox" } },
|
||||
},
|
||||
resources: {
|
||||
title: "tropos o gen",
|
||||
resources: messagePack({
|
||||
discord: messagePack({
|
||||
resources: {
|
||||
discord: {
|
||||
title: "server o Diskord",
|
||||
subtitle: "axilkun ge genilkun po ce! wekatutsa!",
|
||||
desc: "danzalil hez server po 2015. ibe dutukun musra po ce, de ibe wiftutsakun dof po pam, de wekatukun po server!",
|
||||
image: messagePack({ src: fallback, alt: "surat o Diskord" }),
|
||||
buttons: messagePack({
|
||||
join: messagePack({ label: "wekatutsa" }),
|
||||
rules: messagePack({ label: "musra" }),
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
kotoba: messagePack({
|
||||
buttons: {
|
||||
join: { label: "wekatutsa" },
|
||||
rules: { label: "musra" },
|
||||
},
|
||||
},
|
||||
},
|
||||
images: { discordLogo: { alt: "surat o Diskord" } },
|
||||
},
|
||||
kotoba: {
|
||||
title: "zalkuketutsa mot o viosox mit il o omni falmot",
|
||||
searchHelp:
|
||||
"ibe tastatukun il falmot o mot o viosox po pam, de zalkuketukun.",
|
||||
}),
|
||||
} as const) satisfies DeepPartialLocale<LocaleMask>;
|
||||
},
|
||||
} as const satisfies DeepPartial<LocaleMask>;
|
||||
|
|
|
|||
|
|
@ -2,23 +2,46 @@
|
|||
import HomeSectionWrapper from "@/components/molecules/HomeSectionWrapper.vue";
|
||||
import { useLocale } from "@/i18n";
|
||||
import { GREETINGS, type Greeting } from "@/i18n/greeting";
|
||||
import type { Locale } from "@/i18n/locale";
|
||||
import type * as i18n from "@/i18n/locale";
|
||||
import { VILANTIC_ID_TO_FLAG } from "@/i18n/vilantic";
|
||||
import { randomElement } from "@/utils/random";
|
||||
import { computed } from "vue";
|
||||
import flakkaImg from "@/assets/flakka.png";
|
||||
|
||||
interface SectionConfig {
|
||||
id: keyof i18n.Locale["home"]["sections"];
|
||||
image?: keyof typeof imagesI18n.value;
|
||||
}
|
||||
|
||||
const SECTION_CONFIGS = [
|
||||
{ id: "whatIsViossa", image: "viossaFlag" },
|
||||
{ id: "historyOfViossa", image: "viossaFlag" },
|
||||
{ id: "community" },
|
||||
] as const satisfies SectionConfig[];
|
||||
|
||||
const locale = useLocale();
|
||||
const homeI18n = computed(() => locale.value.home);
|
||||
|
||||
interface ImageI18n {
|
||||
src: string;
|
||||
metadata: i18n.Image;
|
||||
}
|
||||
|
||||
const imagesI18n = computed(() => {
|
||||
const imagesI18n = homeI18n.value.images;
|
||||
|
||||
return {
|
||||
viossaFlag: { src: flakkaImg, metadata: imagesI18n.viossaFlag },
|
||||
} as const satisfies Record<string, ImageI18n>;
|
||||
});
|
||||
|
||||
const greeting: Greeting = randomElement(GREETINGS);
|
||||
|
||||
const SECTION_ORDER = [
|
||||
"whatIsViossa",
|
||||
"historyOfViossa",
|
||||
"community",
|
||||
] as const satisfies (keyof Locale["home"]["sections"])[];
|
||||
|
||||
const sections = computed(() =>
|
||||
SECTION_ORDER.map((id) => locale.value.home.sections[id]),
|
||||
const sectionsI18n = computed(() =>
|
||||
SECTION_CONFIGS.map(({ id, image }: SectionConfig) => ({
|
||||
text: homeI18n.value.sections[id],
|
||||
image: image && imagesI18n.value[image],
|
||||
})),
|
||||
);
|
||||
</script>
|
||||
|
||||
|
|
@ -46,12 +69,12 @@ const sections = computed(() =>
|
|||
|
||||
<section class="section container">
|
||||
<HomeSectionWrapper
|
||||
v-for="(section, index) in sections"
|
||||
v-for="(sectioni18n, index) in sectionsI18n"
|
||||
:key="index"
|
||||
:title="section.title"
|
||||
:text="section.text"
|
||||
:image="section.image?.src"
|
||||
:alt="section.image?.alt"
|
||||
:title="sectioni18n.text.title"
|
||||
:text="sectioni18n.text.body"
|
||||
:image="sectioni18n.image?.src"
|
||||
:alt="sectioni18n.image?.metadata.alt"
|
||||
:reverse="index % 2 !== 0" />
|
||||
</section>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -3,30 +3,56 @@ import LearningResourceWrapper, {
|
|||
type ResourceButton,
|
||||
} from "@/components/molecules/LearningResourceWrapper.vue";
|
||||
import { useLocale, type CompileLocale } from "@/i18n";
|
||||
import type { Locale } from "@/i18n/locale";
|
||||
import type * as i18n from "@/i18n/locale";
|
||||
import { ignore } from "@/utils/ignore";
|
||||
import { computed } from "vue";
|
||||
import discordImg from "@/assets/discord.png";
|
||||
|
||||
interface ResourceConfig {
|
||||
id: keyof i18n.Locale["resources"]["resources"];
|
||||
image?: keyof typeof imagesI18n.value;
|
||||
}
|
||||
|
||||
const RESOURCE_CONFIGS = [
|
||||
{ id: "discord", image: "discordLogo" },
|
||||
] as const satisfies ResourceConfig[];
|
||||
|
||||
const locale = useLocale();
|
||||
|
||||
const resourceIdToResource = computed(() => locale.value.resources.resources);
|
||||
const pageI18n = computed(() => locale.value.resources);
|
||||
|
||||
const RESOURCE_ORDER = [
|
||||
"discord",
|
||||
] as const satisfies (keyof Locale["resources"]["resources"])[];
|
||||
interface ImageI18n {
|
||||
src: string;
|
||||
metadata: i18n.Image;
|
||||
}
|
||||
|
||||
const resources = computed(() =>
|
||||
RESOURCE_ORDER.map((id) => [id, resourceIdToResource.value[id]] as const),
|
||||
const imagesI18n = computed(() => {
|
||||
const imagesI18n = pageI18n.value.images;
|
||||
|
||||
return {
|
||||
discordLogo: { src: discordImg, metadata: imagesI18n.discordLogo },
|
||||
} as const satisfies Record<string, ImageI18n>;
|
||||
});
|
||||
|
||||
const resourcesI18n = computed(() =>
|
||||
RESOURCE_CONFIGS.map(
|
||||
({ id, image }: ResourceConfig) =>
|
||||
({
|
||||
id,
|
||||
text: pageI18n.value.resources[id],
|
||||
image: image && imagesI18n.value[image],
|
||||
}) as const,
|
||||
),
|
||||
);
|
||||
|
||||
const computeButtons = (
|
||||
id: keyof CompileLocale<Locale>["resources"]["resources"],
|
||||
id: keyof CompileLocale<i18n.Locale>["resources"]["resources"],
|
||||
): ResourceButton[] => {
|
||||
// will warn us if a new variant is added that isn't handled, and so we should add a switch
|
||||
// once we have a switch statement, this won't be needed as that will check for exhaustiveness
|
||||
ignore<"discord">(id);
|
||||
|
||||
const buttons = resourceIdToResource.value[id].buttons;
|
||||
const buttons = pageI18n.value.resources[id].buttons;
|
||||
return [
|
||||
{
|
||||
link: {
|
||||
|
|
@ -58,13 +84,18 @@ const computeButtons = (
|
|||
|
||||
<section class="section container">
|
||||
<LearningResourceWrapper
|
||||
v-for="([resourceId, resource], index) in resources"
|
||||
v-for="(resourceI18n, index) in resourcesI18n"
|
||||
:key="index"
|
||||
:title="resource.title"
|
||||
:subtitle="resource.subtitle"
|
||||
:desc="resource.desc"
|
||||
:image="resource.image ?? undefined"
|
||||
:buttons="computeButtons(resourceId)" />
|
||||
:title="resourceI18n.text.title"
|
||||
:subtitle="resourceI18n.text.subtitle"
|
||||
:desc="resourceI18n.text.desc"
|
||||
:image="
|
||||
resourceI18n.image && {
|
||||
src: resourceI18n.image.src,
|
||||
alt: resourceI18n.image.metadata.alt,
|
||||
}
|
||||
"
|
||||
:buttons="computeButtons(resourceI18n.id)" />
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue