mirror of
https://github.com/monkeytypegame/monkeytype.git
synced 2025-10-26 08:47:36 +08:00
refactor: move languages to contracts (@fehmer) (#6497)
This commit is contained in:
parent
ed24f7f45b
commit
eb092cea1c
50 changed files with 1296 additions and 1698 deletions
|
|
@ -188,7 +188,7 @@ describe("Loaderboard Controller", () => {
|
|||
expect(body).toEqual({
|
||||
message: "Invalid query schema",
|
||||
validationErrors: [
|
||||
'"language" Can only contain letters [a-zA-Z0-9_+]',
|
||||
'"language" Invalid enum value. Must be a supported language',
|
||||
`"mode" Invalid enum value. Expected 'time' | 'words' | 'quote' | 'custom' | 'zen', received 'unknownMode'`,
|
||||
'"mode2" Needs to be a number or a number represented as a string e.g. "10".',
|
||||
'"page" Number must be greater than or equal to 0',
|
||||
|
|
@ -344,7 +344,7 @@ describe("Loaderboard Controller", () => {
|
|||
expect(body).toEqual({
|
||||
message: "Invalid query schema",
|
||||
validationErrors: [
|
||||
'"language" Can only contain letters [a-zA-Z0-9_+]',
|
||||
'"language" Invalid enum value. Must be a supported language',
|
||||
`"mode" Invalid enum value. Expected 'time' | 'words' | 'quote' | 'custom' | 'zen', received 'unknownMode'`,
|
||||
'"mode2" Needs to be a number or a number represented as a string e.g. "10".',
|
||||
],
|
||||
|
|
@ -652,7 +652,7 @@ describe("Loaderboard Controller", () => {
|
|||
expect(body).toEqual({
|
||||
message: "Invalid query schema",
|
||||
validationErrors: [
|
||||
'"language" Can only contain letters [a-zA-Z0-9_+]',
|
||||
'"language" Invalid enum value. Must be a supported language',
|
||||
`"mode" Invalid enum value. Expected 'time' | 'words' | 'quote' | 'custom' | 'zen', received 'unknownMode'`,
|
||||
'"mode2" Needs to be a number or a number represented as a string e.g. "10".',
|
||||
],
|
||||
|
|
@ -830,7 +830,7 @@ describe("Loaderboard Controller", () => {
|
|||
expect(body).toEqual({
|
||||
message: "Invalid query schema",
|
||||
validationErrors: [
|
||||
'"language" Can only contain letters [a-zA-Z0-9_+]',
|
||||
'"language" Invalid enum value. Must be a supported language',
|
||||
`"mode" Invalid enum value. Expected 'time' | 'words' | 'quote' | 'custom' | 'zen', received 'unknownMode'`,
|
||||
'"mode2" Needs to be a number or a number represented as a string e.g. "10".',
|
||||
],
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ describe("PublicController", () => {
|
|||
expect(body).toEqual({
|
||||
message: "Invalid query schema",
|
||||
validationErrors: [
|
||||
'"language" Can only contain letters [a-zA-Z0-9_+]',
|
||||
'"language" Invalid enum value. Must be a supported language',
|
||||
`"mode" Invalid enum value. Expected 'time' | 'words' | 'quote' | 'custom' | 'zen', received 'unknownMode'`,
|
||||
'"mode2" Needs to be a number or a number represented as a string e.g. "10".',
|
||||
],
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import { roundTo2 } from "@monkeytype/util/numbers";
|
|||
import { MonkeyRequest } from "../types";
|
||||
import { DBResult } from "../../utils/result";
|
||||
import { LbPersonalBests } from "../../utils/pb";
|
||||
import { Language } from "@monkeytype/contracts/schemas/languages";
|
||||
|
||||
const CREATE_RESULT_DEFAULT_OPTIONS = {
|
||||
firstTestTimestamp: DateUtils.startOfDay(new UTCDate(Date.now())).valueOf(),
|
||||
|
|
@ -207,7 +208,7 @@ async function updateUser(uid: string): Promise<void> {
|
|||
const modes = stats.map(
|
||||
(it) =>
|
||||
it["_id"] as {
|
||||
language: string;
|
||||
language: Language;
|
||||
mode: "time" | "custom" | "words" | "quote" | "zen";
|
||||
mode2: `${number}` | "custom" | "zen";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import {
|
|||
} from "@monkeytype/contracts/quotes";
|
||||
import { replaceObjectId, replaceObjectIds } from "../../utils/misc";
|
||||
import { MonkeyRequest } from "../types";
|
||||
import { Language } from "@monkeytype/contracts/schemas/languages";
|
||||
|
||||
async function verifyCaptcha(captcha: string): Promise<void> {
|
||||
if (!(await verify(captcha))) {
|
||||
|
|
@ -36,9 +37,9 @@ export async function getQuotes(
|
|||
const { uid } = req.ctx.decodedToken;
|
||||
const quoteMod = (await getPartialUser(uid, "get quotes", ["quoteMod"]))
|
||||
.quoteMod;
|
||||
const quoteModString = quoteMod === true ? "all" : (quoteMod as string);
|
||||
const quoteModLanguage = quoteMod === true ? "all" : (quoteMod as Language);
|
||||
|
||||
const data = await NewQuotesDAL.get(quoteModString);
|
||||
const data = await NewQuotesDAL.get(quoteModLanguage);
|
||||
return new MonkeyResponse(
|
||||
"Quote submissions retrieved",
|
||||
replaceObjectIds(data)
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import { WithObjectId } from "../utils/misc";
|
|||
import { parseWithSchema as parseJsonWithSchema } from "@monkeytype/util/json";
|
||||
import { z } from "zod";
|
||||
import { tryCatchSync } from "@monkeytype/util/trycatch";
|
||||
import { Language } from "@monkeytype/contracts/schemas/languages";
|
||||
|
||||
const JsonQuoteSchema = z.object({
|
||||
text: z.string(),
|
||||
|
|
@ -112,11 +113,11 @@ export async function add(
|
|||
return undefined;
|
||||
}
|
||||
|
||||
export async function get(language: string): Promise<DBNewQuote[]> {
|
||||
export async function get(language: Language | "all"): Promise<DBNewQuote[]> {
|
||||
if (git === undefined) throw new MonkeyError(500, "Git not available.");
|
||||
const where: {
|
||||
approved: boolean;
|
||||
language?: string;
|
||||
language?: Language;
|
||||
} = {
|
||||
approved: false,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import { QuoteRating } from "@monkeytype/contracts/schemas/quotes";
|
|||
import * as db from "../init/db";
|
||||
import { Collection } from "mongodb";
|
||||
import { WithObjectId } from "../utils/misc";
|
||||
import { Language } from "@monkeytype/contracts/schemas/languages";
|
||||
|
||||
type DBQuoteRating = WithObjectId<QuoteRating>;
|
||||
|
||||
|
|
@ -11,7 +12,7 @@ export const getQuoteRatingCollection = (): Collection<DBQuoteRating> =>
|
|||
|
||||
export async function submit(
|
||||
quoteId: number,
|
||||
language: string,
|
||||
language: Language,
|
||||
rating: number,
|
||||
update: boolean
|
||||
): Promise<void> {
|
||||
|
|
@ -47,7 +48,7 @@ export async function submit(
|
|||
|
||||
export async function get(
|
||||
quoteId: number,
|
||||
language: string
|
||||
language: Language
|
||||
): Promise<DBQuoteRating | null> {
|
||||
return await getQuoteRatingCollection().findOne({ quoteId, language });
|
||||
}
|
||||
|
|
|
|||
|
|
@ -59,7 +59,7 @@ const permissionChecks: Record<PermissionId, PermissionCheck> = {
|
|||
["quoteMod"],
|
||||
(user) =>
|
||||
user.quoteMod === true ||
|
||||
(typeof user.quoteMod === "string" && user.quoteMod !== "")
|
||||
(typeof user.quoteMod === "string" && (user.quoteMod as string) !== "")
|
||||
),
|
||||
canReport: buildUserPermission(
|
||||
["canReport"],
|
||||
|
|
|
|||
|
|
@ -31,35 +31,28 @@ The contents of the file should be as follows:
|
|||
It is recommended that you familiarize yourselves with JSON before adding a language. For the `name` field, put the name of your language. `rightToLeft` indicates how the language is written. If it is written right to left then put `true`, otherwise put `false`.
|
||||
`ligatures` A ligature occurs when multiple letters are joined together to form a character [more details](<https://en.wikipedia.org/wiki/Ligature_(writing)>). If there's joining in the words, which is the case in languages like (Arabic, Malayalam, Persian, Sanskrit, Central_Kurdish... etc.), then set the value to `true`, otherwise set it to `false`. For `bcp47` put your languages [IETF language tag](https://en.wikipedia.org/wiki/IETF_language_tag). If the words you're adding are ordered by frequency (most common words at the top, least at the bottom) set the value of `orderedByFrequency` to `true`, otherwise `false`. Finally, add your list of words to the `words` field.
|
||||
|
||||
In addition to the language file, you need to add your language to the `_groups.json` and `_list.json` files in the same directory. Add the name of the language to the `_groups.json` file like so:
|
||||
Then, go to `packages/contracts/src/schemas/languages.ts` and add your new language name at the _end_ of the `LanguageSchema` enum. Make sure to end the line with a comma. Make sure to add all your language names if you have created multiple word lists of differing lengths in the same language.
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "spanish",
|
||||
"languages": ["spanish", "spanish_1k", "spanish_10k"]
|
||||
},
|
||||
{
|
||||
"name": "YOUR_LANGUAGE",
|
||||
"languages": ["YOUR_LANGUAGES"]
|
||||
},
|
||||
{
|
||||
"name": "french",
|
||||
"languages": ["french", "french_1k", "french_2k", "french_10k"]
|
||||
},
|
||||
```typescript
|
||||
export const LanguageSchema = z.enum([
|
||||
"english",
|
||||
"english_1k",
|
||||
...
|
||||
"your_language_name",
|
||||
"your_language_name_10k",
|
||||
]);
|
||||
```
|
||||
|
||||
The `languages` field is the list of files that you have created for your language (without the `.json` file extension). Make sure to add all your files if you have created multiple word lists of differing lengths in the same language.
|
||||
Then, go to `frontend/src/ts/constants/language.ts` and add your new language name to the `LanguageGroups` map. You can either add it to an existing group or add a new one. Make sure to add all your language names if you have created multiple word lists of differing lengths in the same language.
|
||||
|
||||
Add your language lists to the `_list.json` file like so:
|
||||
|
||||
```json
|
||||
,"spanish"
|
||||
,"spanish_1k"
|
||||
,"spanish_10k"
|
||||
,"YOUR_LANGUAGE"
|
||||
,"french"
|
||||
,"french_1k"
|
||||
,"french_2k"
|
||||
```typescript
|
||||
export const LanguageGroups: Record<string, Language[]> = {
|
||||
...
|
||||
your_language_name: [
|
||||
"your_language_name",
|
||||
"your_language_name_10k",
|
||||
]
|
||||
};
|
||||
```
|
||||
|
||||
### Committing Languages
|
||||
|
|
|
|||
67
frontend/__tests__/constants/languages.spec.ts
Normal file
67
frontend/__tests__/constants/languages.spec.ts
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
import { readdirSync } from "fs";
|
||||
import { LanguageGroups, LanguageList } from "../../src/ts/constants/languages";
|
||||
import { Language } from "@monkeytype/contracts/schemas/languages";
|
||||
|
||||
describe("languages", () => {
|
||||
describe("LanguageList", () => {
|
||||
it("should not have duplicates", () => {
|
||||
const duplicates = LanguageList.filter(
|
||||
(item, index) => LanguageList.indexOf(item) !== index
|
||||
);
|
||||
expect(duplicates).toEqual([]);
|
||||
});
|
||||
it("should have all related json files", () => {
|
||||
const languageFiles = listLanguageFiles();
|
||||
|
||||
const missingLanguageFiles = LanguageList.filter(
|
||||
(it) => !languageFiles.includes(it)
|
||||
).map((it) => `fontend/static/languages/${it}.json`);
|
||||
|
||||
expect(missingLanguageFiles, "missing language json files").toEqual([]);
|
||||
});
|
||||
it("should not have additional related json files", () => {
|
||||
const LanguageFiles = listLanguageFiles();
|
||||
|
||||
const additionalLanguageFiles = LanguageFiles.filter(
|
||||
(it) => !LanguageList.some((language) => language === it)
|
||||
).map((it) => `fontend/static/languages/${it}.json`);
|
||||
|
||||
expect(
|
||||
additionalLanguageFiles,
|
||||
"additional language json files not declared in frontend/src/ts/constants/languages.ts"
|
||||
).toEqual([]);
|
||||
});
|
||||
});
|
||||
describe("LanguageGroups", () => {
|
||||
it("should contain each language once", () => {
|
||||
const languagesWithMultipleGroups = [];
|
||||
|
||||
const groupByLanguage = new Map<Language, string>();
|
||||
|
||||
for (const group of Object.keys(LanguageGroups)) {
|
||||
for (const language of LanguageGroups[group] as Language[]) {
|
||||
if (groupByLanguage.has(language)) {
|
||||
languagesWithMultipleGroups.push(language);
|
||||
}
|
||||
groupByLanguage.set(language, group);
|
||||
}
|
||||
}
|
||||
|
||||
expect(
|
||||
languagesWithMultipleGroups,
|
||||
"languages with multiple groups"
|
||||
).toEqual([]);
|
||||
|
||||
expect(
|
||||
Array.from(groupByLanguage.keys()).sort(),
|
||||
"every language has a group"
|
||||
).toEqual(LanguageList.sort());
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
function listLanguageFiles() {
|
||||
return readdirSync(import.meta.dirname + "/../../static/languages").map(
|
||||
(it) => it.substring(0, it.length - 5) as Language
|
||||
);
|
||||
}
|
||||
|
|
@ -423,11 +423,8 @@ describe("Config", () => {
|
|||
it("setLanguage", () => {
|
||||
expect(Config.setLanguage("english")).toBe(true);
|
||||
expect(Config.setLanguage("english_1k")).toBe(true);
|
||||
expect(Config.setLanguage(stringOfLength(50))).toBe(true);
|
||||
|
||||
expect(Config.setLanguage("english 1k")).toBe(false);
|
||||
expect(Config.setLanguage("english-1k")).toBe(false);
|
||||
expect(Config.setLanguage(stringOfLength(51))).toBe(false);
|
||||
expect(Config.setLanguage("invalid" as any)).toBe(false);
|
||||
});
|
||||
it("setKeymapLayout", () => {
|
||||
expect(Config.setKeymapLayout("overrideSync")).toBe(true);
|
||||
|
|
|
|||
|
|
@ -391,58 +391,9 @@ function validateQuotes() {
|
|||
|
||||
function validateLanguages() {
|
||||
return new Promise((resolve, reject) => {
|
||||
//languages
|
||||
const languagesData = JSON.parse(
|
||||
fs.readFileSync("./static/languages/_list.json", {
|
||||
encoding: "utf8",
|
||||
flag: "r",
|
||||
})
|
||||
);
|
||||
const languagesSchema = {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "string",
|
||||
},
|
||||
};
|
||||
const languagesValidator = ajv.compile(languagesSchema);
|
||||
if (languagesValidator(languagesData)) {
|
||||
console.log("Languages list JSON schema is \u001b[32mvalid\u001b[0m");
|
||||
} else {
|
||||
console.log("Languages list JSON schema is \u001b[31minvalid\u001b[0m");
|
||||
return reject(new Error(languagesValidator.errors[0].message));
|
||||
}
|
||||
|
||||
//languages group
|
||||
const languagesGroupData = JSON.parse(
|
||||
fs.readFileSync("./static/languages/_groups.json", {
|
||||
encoding: "utf8",
|
||||
flag: "r",
|
||||
})
|
||||
);
|
||||
const languagesGroupSchema = {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "object",
|
||||
properties: {
|
||||
name: { type: "string" },
|
||||
languages: {
|
||||
type: "array",
|
||||
items: {
|
||||
type: "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
required: ["name", "languages"],
|
||||
},
|
||||
};
|
||||
const languagesGroupValidator = ajv.compile(languagesGroupSchema);
|
||||
if (languagesGroupValidator(languagesGroupData)) {
|
||||
console.log("Languages groups JSON schema is \u001b[32mvalid\u001b[0m");
|
||||
} else {
|
||||
console.log("Languages groups JSON schema is \u001b[31minvalid\u001b[0m");
|
||||
return reject(new Error(languagesGroupValidator.errors[0].message));
|
||||
}
|
||||
|
||||
const languages = fs
|
||||
.readdirSync("./static/languages")
|
||||
.map((it) => it.substring(0, it.length - 5));
|
||||
//language files
|
||||
const languageFileSchema = {
|
||||
type: "object",
|
||||
|
|
@ -472,7 +423,7 @@ function validateLanguages() {
|
|||
let languageFilesErrors;
|
||||
const duplicatePercentageThreshold = 0.0001;
|
||||
let langsWithDuplicates = 0;
|
||||
languagesData.forEach((language) => {
|
||||
languages.forEach((language) => {
|
||||
const languageFileData = JSON.parse(
|
||||
fs.readFileSync(`./static/languages/${language}.json`, {
|
||||
encoding: "utf8",
|
||||
|
|
|
|||
|
|
@ -504,14 +504,28 @@
|
|||
<i class="fas fa-gamepad"></i>
|
||||
funbox
|
||||
</div>
|
||||
<div class="select filterGroup" group="funbox"></div>
|
||||
<div class="select filterGroup" group="funbox">
|
||||
<select
|
||||
class="funboxSelect"
|
||||
group="funbox"
|
||||
placeholder="select a funbox"
|
||||
multiple
|
||||
></select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="buttonsAndTitle languages">
|
||||
<div class="title">
|
||||
<i class="fas fa-globe-americas"></i>
|
||||
language
|
||||
</div>
|
||||
<div class="select filterGroup" group="language"></div>
|
||||
<div class="select filterGroup" group="language">
|
||||
<select
|
||||
class="languageSelect"
|
||||
group="language"
|
||||
placeholder="select a language"
|
||||
multiple
|
||||
></select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -84,9 +84,7 @@ import LoadChallengeCommands, {
|
|||
import FontFamilyCommands, {
|
||||
update as updateFontFamilyCommands,
|
||||
} from "./lists/font-family";
|
||||
import LanguagesCommands, {
|
||||
update as updateLanguagesCommands,
|
||||
} from "./lists/languages";
|
||||
import LanguagesCommands from "./lists/languages";
|
||||
import KeymapLayoutsCommands from "./lists/keymap-layouts";
|
||||
|
||||
import Config, * as UpdateConfig from "../config";
|
||||
|
|
@ -107,17 +105,7 @@ import {
|
|||
import { Command, CommandsSubgroup } from "./types";
|
||||
import * as TestLogic from "../test/test-logic";
|
||||
import * as ActivePage from "../states/active-page";
|
||||
|
||||
const languagesPromise = JSONData.getLanguageList();
|
||||
languagesPromise
|
||||
.then((languages) => {
|
||||
updateLanguagesCommands(languages);
|
||||
})
|
||||
.catch((e: unknown) => {
|
||||
console.error(
|
||||
Misc.createErrorMessage(e, "Failed to update language commands")
|
||||
);
|
||||
});
|
||||
import { Language } from "@monkeytype/contracts/schemas/languages";
|
||||
|
||||
const fontsPromise = JSONData.getFontsList();
|
||||
fontsPromise
|
||||
|
|
@ -226,7 +214,7 @@ export const commands: CommandsSubgroup = {
|
|||
icon: "fa-language",
|
||||
exec: ({ input }): void => {
|
||||
if (input === undefined) return;
|
||||
void UpdateConfig.setCustomPolyglot(input.split(" "));
|
||||
void UpdateConfig.setCustomPolyglot(input.split(" ") as Language[]);
|
||||
if (ActivePage.get() === "test") {
|
||||
TestLogic.restart();
|
||||
}
|
||||
|
|
@ -490,7 +478,8 @@ export function doesListExist(listName: string): boolean {
|
|||
export async function getList(
|
||||
listName: ListsObjectKeys
|
||||
): Promise<CommandsSubgroup> {
|
||||
await Promise.allSettled([languagesPromise, fontsPromise, challengesPromise]);
|
||||
await Promise.allSettled([fontsPromise, challengesPromise]);
|
||||
|
||||
const list = lists[listName];
|
||||
if (!list) {
|
||||
Notifications.add(`List not found: ${listName}`, -1);
|
||||
|
|
@ -531,8 +520,7 @@ export function getTopOfStack(): CommandsSubgroup {
|
|||
|
||||
let singleList: CommandsSubgroup | undefined;
|
||||
export async function getSingleSubgroup(): Promise<CommandsSubgroup> {
|
||||
await Promise.allSettled([languagesPromise, fontsPromise, challengesPromise]);
|
||||
|
||||
await Promise.allSettled([fontsPromise, challengesPromise]);
|
||||
const singleCommands: Command[] = [];
|
||||
for (const command of commands.list) {
|
||||
const ret = buildSingleListCommands(command);
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import * as UpdateConfig from "../../config";
|
||||
import { LanguageList } from "../../constants/languages";
|
||||
import {
|
||||
capitalizeFirstLetterOfEachWord,
|
||||
getLanguageDisplayString,
|
||||
|
|
@ -8,12 +9,14 @@ import { Command, CommandsSubgroup } from "../types";
|
|||
const subgroup: CommandsSubgroup = {
|
||||
title: "Language...",
|
||||
configKey: "language",
|
||||
list: [
|
||||
{
|
||||
id: "couldnotload",
|
||||
display: "Could not load the languages list :(",
|
||||
list: LanguageList.map((language) => ({
|
||||
id: "changeLanguage" + capitalizeFirstLetterOfEachWord(language),
|
||||
display: getLanguageDisplayString(language),
|
||||
configValue: language,
|
||||
exec: (): void => {
|
||||
UpdateConfig.setLanguage(language);
|
||||
},
|
||||
],
|
||||
})),
|
||||
};
|
||||
|
||||
const commands: Command[] = [
|
||||
|
|
@ -25,19 +28,4 @@ const commands: Command[] = [
|
|||
},
|
||||
];
|
||||
|
||||
function update(languages: string[]): void {
|
||||
subgroup.list = [];
|
||||
languages.forEach((language) => {
|
||||
subgroup.list.push({
|
||||
id: "changeLanguage" + capitalizeFirstLetterOfEachWord(language),
|
||||
display: getLanguageDisplayString(language),
|
||||
configValue: language,
|
||||
exec: (): void => {
|
||||
UpdateConfig.setLanguage(language);
|
||||
},
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export default commands;
|
||||
export { update };
|
||||
|
|
|
|||
|
|
@ -24,7 +24,10 @@ import {
|
|||
import * as ConfigSchemas from "@monkeytype/contracts/schemas/configs";
|
||||
import { Config, FunboxName } from "@monkeytype/contracts/schemas/configs";
|
||||
import { Mode, ModeSchema } from "@monkeytype/contracts/schemas/shared";
|
||||
import { Language, LanguageSchema } from "@monkeytype/contracts/schemas/util";
|
||||
import {
|
||||
Language,
|
||||
LanguageSchema,
|
||||
} from "@monkeytype/contracts/schemas/languages";
|
||||
import { LocalStorageWithSchema } from "./utils/local-storage-with-schema";
|
||||
import { migrateConfig } from "./utils/config";
|
||||
import { roundTo1 } from "@monkeytype/util/numbers";
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import {
|
|||
TestActivityCalendar,
|
||||
} from "../elements/test-activity-calendar";
|
||||
import { Preset } from "@monkeytype/contracts/schemas/presets";
|
||||
import { Language } from "@monkeytype/contracts/schemas/languages";
|
||||
|
||||
export type SnapshotUserTag = UserTag & {
|
||||
active?: boolean;
|
||||
|
|
@ -43,7 +44,7 @@ export type SnapshotResult<M extends Mode> = Omit<
|
|||
lazyMode: boolean;
|
||||
difficulty: string;
|
||||
funbox: FunboxName[];
|
||||
language: string;
|
||||
language: Language;
|
||||
numbers: boolean;
|
||||
punctuation: boolean;
|
||||
quoteLength: number;
|
||||
|
|
|
|||
366
frontend/src/ts/constants/languages.ts
Normal file
366
frontend/src/ts/constants/languages.ts
Normal file
|
|
@ -0,0 +1,366 @@
|
|||
import {
|
||||
Language,
|
||||
LanguageSchema,
|
||||
} from "@monkeytype/contracts/schemas/languages";
|
||||
|
||||
export const LanguageList: Language[] = LanguageSchema._def.values;
|
||||
|
||||
export const LanguageGroups: Record<string, Language[]> = {
|
||||
english: [
|
||||
"english",
|
||||
"english_1k",
|
||||
"english_5k",
|
||||
"english_10k",
|
||||
"english_25k",
|
||||
"english_450k",
|
||||
"english_commonly_misspelled",
|
||||
"english_contractions",
|
||||
"english_doubleletter",
|
||||
"english_shakespearean",
|
||||
"english_old",
|
||||
"english_medical",
|
||||
],
|
||||
spanish: ["spanish", "spanish_1k", "spanish_10k", "spanish_650k"],
|
||||
french: [
|
||||
"french",
|
||||
"french_1k",
|
||||
"french_2k",
|
||||
"french_10k",
|
||||
"french_600k",
|
||||
"french_bitoduc",
|
||||
],
|
||||
german: ["german", "german_1k", "german_10k", "german_250k"],
|
||||
swiss_german: ["swiss_german", "swiss_german_1k", "swiss_german_2k"],
|
||||
portuguese: [
|
||||
"portuguese",
|
||||
"portuguese_1k",
|
||||
"portuguese_3k",
|
||||
"portuguese_5k",
|
||||
"portuguese_320k",
|
||||
"portuguese_550k",
|
||||
"portuguese_acentos_e_cedilha",
|
||||
],
|
||||
arabic: ["arabic", "arabic_10k"],
|
||||
arabic_egypt: ["arabic_egypt", "arabic_egypt_1k"],
|
||||
italian: [
|
||||
"italian",
|
||||
"italian_1k",
|
||||
"italian_7k",
|
||||
"italian_60k",
|
||||
"italian_280k",
|
||||
],
|
||||
friulian: ["friulian"],
|
||||
latin: ["latin"],
|
||||
afrikaans: ["afrikaans", "afrikaans_1k", "afrikaans_10k"],
|
||||
mongolian: ["mongolian", "mongolian_10k"],
|
||||
korean: ["korean", "korean_1k", "korean_5k"],
|
||||
khmer: ["khmer"],
|
||||
marathi: ["marathi"],
|
||||
chinese: [
|
||||
"chinese_traditional",
|
||||
"chinese_simplified",
|
||||
"chinese_simplified_1k",
|
||||
"chinese_simplified_5k",
|
||||
"chinese_simplified_10k",
|
||||
"chinese_simplified_50k",
|
||||
],
|
||||
russian: [
|
||||
"russian",
|
||||
"russian_1k",
|
||||
"russian_5k",
|
||||
"russian_10k",
|
||||
"russian_25k",
|
||||
"russian_50k",
|
||||
"russian_375k",
|
||||
"russian_contractions",
|
||||
"russian_contractions_1k",
|
||||
"russian_abbreviations",
|
||||
],
|
||||
polish: [
|
||||
"polish",
|
||||
"polish_2k",
|
||||
"polish_5k",
|
||||
"polish_10k",
|
||||
"polish_20k",
|
||||
"polish_40k",
|
||||
"polish_200k",
|
||||
],
|
||||
czech: ["czech", "czech_1k", "czech_10k"],
|
||||
slovak: ["slovak", "slovak_1k", "slovak_10k"],
|
||||
ukrainian: [
|
||||
"ukrainian",
|
||||
"ukrainian_1k",
|
||||
"ukrainian_10k",
|
||||
"ukrainian_50k",
|
||||
"ukrainian_endings",
|
||||
],
|
||||
ukrainian_latynka: [
|
||||
"ukrainian_latynka",
|
||||
"ukrainian_latynka_1k",
|
||||
"ukrainian_latynka_10k",
|
||||
"ukrainian_latynka_50k",
|
||||
"ukrainian_latynka_endings",
|
||||
],
|
||||
lithuanian: ["lithuanian", "lithuanian_1k", "lithuanian_3k"],
|
||||
indonesian: ["indonesian", "indonesian_1k", "indonesian_10k"],
|
||||
kurdish_central: [
|
||||
"kurdish_central",
|
||||
"kurdish_central_2k",
|
||||
"kurdish_central_4k",
|
||||
],
|
||||
greek: ["greek", "greek_1k", "greek_5k", "greek_10k", "greek_25k"],
|
||||
greeklish: [
|
||||
"greeklish",
|
||||
"greeklish_1k",
|
||||
"greeklish_5k",
|
||||
"greeklish_10k",
|
||||
"greeklish_25k",
|
||||
],
|
||||
turkish: ["turkish", "turkish_1k", "turkish_5k"],
|
||||
irish: ["irish"],
|
||||
galician: ["galician"],
|
||||
thai: ["thai", "thai_20k"],
|
||||
tamil: ["tamil", "tamil_1k", "tanglish", "tamil_old"],
|
||||
kannada: ["kannada"],
|
||||
telugu: ["telugu", "telugu_1k"],
|
||||
slovenian: ["slovenian", "slovenian_1k", "slovenian_5k"],
|
||||
croatian: ["croatian", "croatian_1k"],
|
||||
dutch: ["dutch", "dutch_1k", "dutch_10k"],
|
||||
filipino: ["filipino", "filipino_1k"],
|
||||
danish: ["danish", "danish_1k", "danish_10k"],
|
||||
hungarian: ["hungarian", "hungarian_2k"],
|
||||
norwegian_bokmal: [
|
||||
"norwegian_bokmal",
|
||||
"norwegian_bokmal_1k",
|
||||
"norwegian_bokmal_5k",
|
||||
"norwegian_bokmal_10k",
|
||||
"norwegian_bokmal_150k",
|
||||
"norwegian_bokmal_600k",
|
||||
],
|
||||
norwegian_nynorsk: [
|
||||
"norwegian_nynorsk",
|
||||
"norwegian_nynorsk_1k",
|
||||
"norwegian_nynorsk_5k",
|
||||
"norwegian_nynorsk_10k",
|
||||
"norwegian_nynorsk_100k",
|
||||
"norwegian_nynorsk_400k",
|
||||
],
|
||||
hebrew: ["hebrew", "hebrew_1k", "hebrew_5k", "hebrew_10k"],
|
||||
icelandic: ["icelandic_1k"],
|
||||
malagasy: ["malagasy", "malagasy_1k"],
|
||||
malay: ["malay", "malay_1k"],
|
||||
romanian: [
|
||||
"romanian",
|
||||
"romanian_1k",
|
||||
"romanian_5k",
|
||||
"romanian_10k",
|
||||
"romanian_25k",
|
||||
"romanian_50k",
|
||||
"romanian_100k",
|
||||
"romanian_200k",
|
||||
],
|
||||
finnish: ["finnish", "finnish_1k", "finnish_10k"],
|
||||
estonian: ["estonian", "estonian_1k", "estonian_5k", "estonian_10k"],
|
||||
udmurt: ["udmurt"],
|
||||
welsh: ["welsh", "welsh_1k"],
|
||||
persian: [
|
||||
"persian",
|
||||
"persian_1k",
|
||||
"persian_5k",
|
||||
"persian_20k",
|
||||
"persian_romanized",
|
||||
],
|
||||
kazakh: ["kazakh", "kazakh_1k"],
|
||||
vietnamese: ["vietnamese", "vietnamese_1k", "vietnamese_5k"],
|
||||
jyutping: ["jyutping"],
|
||||
pinyin: ["pinyin", "pinyin_1k", "pinyin_10k"],
|
||||
hausa: ["hausa", "hausa_1k"],
|
||||
swedish: ["swedish", "swedish_1k", "swedish_diacritics"],
|
||||
serbian: ["serbian", "serbian_latin", "serbian_10k", "serbian_latin_10k"],
|
||||
georgian: ["georgian"],
|
||||
yoruba: ["yoruba_1k"],
|
||||
swahili: ["swahili_1k"],
|
||||
maori: ["maori_1k"],
|
||||
catalan: ["catalan", "catalan_1k"],
|
||||
bulgarian: ["bulgarian", "bulgarian_latin"],
|
||||
bosnian: ["bosnian", "bosnian_4k"],
|
||||
esperanto: [
|
||||
"esperanto",
|
||||
"esperanto_1k",
|
||||
"esperanto_10k",
|
||||
"esperanto_25k",
|
||||
"esperanto_36k",
|
||||
"esperanto_x_sistemo",
|
||||
"esperanto_x_sistemo_1k",
|
||||
"esperanto_x_sistemo_10k",
|
||||
"esperanto_x_sistemo_25k",
|
||||
"esperanto_x_sistemo_36k",
|
||||
"esperanto_h_sistemo",
|
||||
"esperanto_h_sistemo_1k",
|
||||
"esperanto_h_sistemo_10k",
|
||||
"esperanto_h_sistemo_25k",
|
||||
"esperanto_h_sistemo_36k",
|
||||
],
|
||||
bangla: ["bangla", "bangla_letters", "bangla_10k"],
|
||||
urdu: ["urdu", "urdu_1k", "urdu_5k", "urdish"],
|
||||
albanian: ["albanian", "albanian_1k"],
|
||||
shona: ["shona", "shona_1k"],
|
||||
armenian: [
|
||||
"armenian",
|
||||
"armenian_1k",
|
||||
"armenian_western",
|
||||
"armenian_western_1k",
|
||||
],
|
||||
myanmar: ["myanmar_burmese"],
|
||||
japanese: [
|
||||
"japanese_hiragana",
|
||||
"japanese_katakana",
|
||||
"japanese_romaji",
|
||||
"japanese_romaji_1k",
|
||||
],
|
||||
hindi: ["hindi", "hindi_1k", "hinglish"],
|
||||
sanskrit: ["sanskrit", "sanskrit_roman"],
|
||||
gujarati: ["gujarati", "gujarati_1k"],
|
||||
nepali: ["nepali", "nepali_1k", "nepali_romanized"],
|
||||
santali: ["santali"],
|
||||
macedonian: [
|
||||
"macedonian",
|
||||
"macedonian_1k",
|
||||
"macedonian_10k",
|
||||
"macedonian_75k",
|
||||
],
|
||||
uzbek: ["uzbek", "uzbek_1k", "uzbek_70k"],
|
||||
belarusian: [
|
||||
"belarusian",
|
||||
"belarusian_1k",
|
||||
"belarusian_5k",
|
||||
"belarusian_10k",
|
||||
"belarusian_25k",
|
||||
"belarusian_50k",
|
||||
"belarusian_100k",
|
||||
],
|
||||
belarusian_lacinka: ["belarusian_lacinka", "belarusian_lacinka_1k"],
|
||||
tatar: ["tatar", "tatar_1k", "tatar_5k", "tatar_9k"],
|
||||
tatar_crimean: [
|
||||
"tatar_crimean",
|
||||
"tatar_crimean_1k",
|
||||
"tatar_crimean_5k",
|
||||
"tatar_crimean_10k",
|
||||
"tatar_crimean_15k",
|
||||
"tatar_crimean_cyrillic",
|
||||
"tatar_crimean_cyrillic_1k",
|
||||
"tatar_crimean_cyrillic_5k",
|
||||
"tatar_crimean_cyrillic_10k",
|
||||
"tatar_crimean_cyrillic_15k",
|
||||
],
|
||||
azerbaijani: ["azerbaijani", "azerbaijani_1k"],
|
||||
malayalam: ["malayalam"],
|
||||
sinhala: ["sinhala"],
|
||||
latvian: ["latvian", "latvian_1k"],
|
||||
maltese: ["maltese", "maltese_1k"],
|
||||
toki_pona: ["toki_pona", "toki_pona_ku_suli", "toki_pona_ku_lili"],
|
||||
xhosa: ["xhosa", "xhosa_3k"],
|
||||
tibetan: ["tibetan", "tibetan_1k"],
|
||||
bashkir: ["bashkir"],
|
||||
other: [
|
||||
"lojban_gismu",
|
||||
"lojban_cmavo",
|
||||
"pig_latin",
|
||||
"twitch_emotes",
|
||||
"git",
|
||||
"typing_of_the_dead",
|
||||
"league_of_legends",
|
||||
"docker_file",
|
||||
],
|
||||
amharic: ["amharic", "amharic_1k", "amharic_5k"],
|
||||
oromo: ["oromo", "oromo_1k", "oromo_5k"],
|
||||
wordle: ["wordle", "wordle_1k"],
|
||||
kyrgyz: ["kyrgyz", "kyrgyz_1k"],
|
||||
yiddish: ["yiddish"],
|
||||
frisian: ["frisian", "frisian_1k"],
|
||||
pashto: ["pashto"],
|
||||
euskera: ["euskera"],
|
||||
klingon: ["klingon", "klingon_1k"],
|
||||
quenya: ["quenya"],
|
||||
lorem_ipsum: ["lorem_ipsum"],
|
||||
occitan: ["occitan", "occitan_1k", "occitan_2k", "occitan_5k", "occitan_10k"],
|
||||
kabyle: ["kabyle", "kabyle_1k", "kabyle_2k", "kabyle_5k", "kabyle_10k"],
|
||||
zulu: ["zulu"],
|
||||
code: [
|
||||
"code_python",
|
||||
"code_python_1k",
|
||||
"code_python_2k",
|
||||
"code_python_5k",
|
||||
"code_c",
|
||||
"code_css",
|
||||
"code_csharp",
|
||||
"code_c++",
|
||||
"code_dart",
|
||||
"code_brainfck",
|
||||
"code_fsharp",
|
||||
"code_javascript",
|
||||
"code_javascript_1k",
|
||||
"code_javascript_react",
|
||||
"code_jule",
|
||||
"code_julia",
|
||||
"code_haskell",
|
||||
"code_html",
|
||||
"code_nim",
|
||||
"code_nix",
|
||||
"code_pascal",
|
||||
"code_java",
|
||||
"code_kotlin",
|
||||
"code_go",
|
||||
"code_rockstar",
|
||||
"code_rust",
|
||||
"code_ruby",
|
||||
"code_r",
|
||||
"code_r_2k",
|
||||
"code_swift",
|
||||
"code_scala",
|
||||
"code_bash",
|
||||
"code_powershell",
|
||||
"code_lua",
|
||||
"code_luau",
|
||||
"code_latex",
|
||||
"code_typst",
|
||||
"code_matlab",
|
||||
"code_sql",
|
||||
"code_perl",
|
||||
"code_php",
|
||||
"code_vim",
|
||||
"code_vimscript",
|
||||
"code_opencl",
|
||||
"code_visual_basic",
|
||||
"code_arduino",
|
||||
"code_systemverilog",
|
||||
"code_elixir",
|
||||
"code_zig",
|
||||
"code_gdscript",
|
||||
"code_gdscript_2",
|
||||
"code_assembly",
|
||||
"code_v",
|
||||
"code_ook",
|
||||
"code_typescript",
|
||||
"code_cobol",
|
||||
"code_common_lisp",
|
||||
"code_odin",
|
||||
"code_fortran",
|
||||
],
|
||||
};
|
||||
|
||||
export type LanguageGroupName = keyof typeof LanguageGroups;
|
||||
export const LanguageGroupNames: LanguageGroupName[] = Array.from(
|
||||
Object.keys(LanguageGroups)
|
||||
);
|
||||
|
||||
/**
|
||||
* Fetches the language group for a given language.
|
||||
* @param language The language code.
|
||||
* @returns the language group.
|
||||
*/
|
||||
export function getGroupForLanguage(
|
||||
language: Language
|
||||
): LanguageGroupName | undefined {
|
||||
return LanguageGroupNames.find((group) => group.includes(language));
|
||||
}
|
||||
|
|
@ -3,7 +3,6 @@ import * as Notifications from "../elements/notifications";
|
|||
import Config, * as UpdateConfig from "../config";
|
||||
import * as AccountButton from "../elements/account-button";
|
||||
import * as Misc from "../utils/misc";
|
||||
import * as JSONData from "../utils/json-data";
|
||||
import * as Settings from "../pages/settings";
|
||||
import * as DB from "../db";
|
||||
import * as TestLogic from "../test/test-logic";
|
||||
|
|
@ -50,6 +49,7 @@ import * as PSA from "../elements/psa";
|
|||
import defaultResultFilters from "../constants/default-result-filters";
|
||||
import { getActiveFunboxesWithFunction } from "../test/funbox/list";
|
||||
import { Snapshot } from "../constants/default-snapshot";
|
||||
import { LanguageList } from "../constants/languages";
|
||||
import * as Sentry from "../sentry";
|
||||
|
||||
export const gmailProvider = new GoogleAuthProvider();
|
||||
|
|
@ -136,26 +136,15 @@ async function getDataAndInit(): Promise<boolean> {
|
|||
|
||||
ResultFilters.loadTags(snapshot.tags);
|
||||
|
||||
Promise.all([JSONData.getLanguageList(), getAllFunboxes()])
|
||||
.then((values) => {
|
||||
const [languages, funboxes] = values;
|
||||
languages.forEach((language) => {
|
||||
defaultResultFilters.language[language] = true;
|
||||
});
|
||||
funboxes.forEach((funbox) => {
|
||||
defaultResultFilters.funbox[funbox.name] = true;
|
||||
});
|
||||
// filters = defaultResultFilters;
|
||||
void ResultFilters.load();
|
||||
})
|
||||
.catch((e: unknown) => {
|
||||
console.log(
|
||||
Misc.createErrorMessage(
|
||||
e,
|
||||
"Something went wrong while loading the filters"
|
||||
)
|
||||
);
|
||||
});
|
||||
for (const language of LanguageList) {
|
||||
defaultResultFilters.language[language] = true;
|
||||
}
|
||||
|
||||
for (const funbox of getAllFunboxes()) {
|
||||
defaultResultFilters.funbox[funbox.name] = true;
|
||||
}
|
||||
// filters = defaultResultFilters;
|
||||
void ResultFilters.load();
|
||||
|
||||
if (snapshot.needsToChangeName) {
|
||||
Notifications.addPSA(
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { subscribe } from "../observables/config-event";
|
|||
import * as DB from "../db";
|
||||
import Ape from "../ape";
|
||||
import { tryCatch } from "@monkeytype/util/trycatch";
|
||||
import { Language } from "@monkeytype/contracts/schemas/languages";
|
||||
|
||||
export type Quote = {
|
||||
text: string;
|
||||
|
|
@ -13,7 +14,7 @@ export type Quote = {
|
|||
length: number;
|
||||
id: number;
|
||||
group: number;
|
||||
language: string;
|
||||
language: Language;
|
||||
textSplit?: string[];
|
||||
};
|
||||
|
||||
|
|
@ -22,7 +23,7 @@ export type QuoteWithTextSplit = Quote & {
|
|||
};
|
||||
|
||||
type QuoteData = {
|
||||
language: string;
|
||||
language: Language;
|
||||
quotes: {
|
||||
text: string;
|
||||
britishText?: string;
|
||||
|
|
@ -54,7 +55,7 @@ class QuotesController {
|
|||
private queueIndex = 0;
|
||||
|
||||
async getQuotes(
|
||||
language: string,
|
||||
language: Language,
|
||||
quoteLengths?: number[]
|
||||
): Promise<QuoteCollection> {
|
||||
const normalizedLanguage = removeLanguageSize(language);
|
||||
|
|
@ -164,7 +165,7 @@ class QuotesController {
|
|||
return randomQuote;
|
||||
}
|
||||
|
||||
getRandomFavoriteQuote(language: string): Quote | null {
|
||||
getRandomFavoriteQuote(language: Language): Quote | null {
|
||||
const snapshot = DB.getSnapshot();
|
||||
if (!snapshot) {
|
||||
return null;
|
||||
|
|
@ -178,7 +179,7 @@ class QuotesController {
|
|||
return null;
|
||||
}
|
||||
|
||||
Object.keys(favoriteQuotes).forEach((language) => {
|
||||
(Object.keys(favoriteQuotes) as Language[]).forEach((language) => {
|
||||
if (removeLanguageSize(language) !== normalizedLanguage) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -210,12 +211,14 @@ class QuotesController {
|
|||
|
||||
const normalizedQuoteLanguage = removeLanguageSize(quoteLanguage);
|
||||
|
||||
const matchedLanguage = Object.keys(favoriteQuotes).find((language) => {
|
||||
if (normalizedQuoteLanguage !== removeLanguageSize(language)) {
|
||||
return false;
|
||||
const matchedLanguage = (Object.keys(favoriteQuotes) as Language[]).find(
|
||||
(language) => {
|
||||
if (normalizedQuoteLanguage !== removeLanguageSize(language)) {
|
||||
return false;
|
||||
}
|
||||
return (favoriteQuotes[language] ?? []).includes(id.toString());
|
||||
}
|
||||
return (favoriteQuotes[language] ?? []).includes(id.toString());
|
||||
});
|
||||
);
|
||||
|
||||
return matchedLanguage !== undefined;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import {
|
|||
import { getDefaultConfig } from "./constants/default-config";
|
||||
import { FunboxMetadata } from "../../../packages/funbox/src/types";
|
||||
import { getFirstDayOfTheWeek } from "./utils/date-and-time";
|
||||
import { Language } from "@monkeytype/contracts/schemas/languages";
|
||||
|
||||
let dbSnapshot: Snapshot | undefined;
|
||||
const firstDayOfTheWeek = getFirstDayOfTheWeek();
|
||||
|
|
@ -659,7 +660,7 @@ export async function saveLocalPB<M extends Mode>(
|
|||
mode2: Mode2<M>,
|
||||
punctuation: boolean,
|
||||
numbers: boolean,
|
||||
language: string,
|
||||
language: Language,
|
||||
difficulty: Difficulty,
|
||||
lazyMode: boolean,
|
||||
wpm: number,
|
||||
|
|
@ -788,7 +789,7 @@ export async function saveLocalTagPB<M extends Mode>(
|
|||
mode2: Mode2<M>,
|
||||
punctuation: boolean,
|
||||
numbers: boolean,
|
||||
language: string,
|
||||
language: Language,
|
||||
difficulty: Difficulty,
|
||||
lazyMode: boolean,
|
||||
wpm: number,
|
||||
|
|
@ -893,7 +894,7 @@ export async function saveLocalTagPB<M extends Mode>(
|
|||
export async function updateLbMemory<M extends Mode>(
|
||||
mode: M,
|
||||
mode2: Mode2<M>,
|
||||
language: string,
|
||||
language: Language,
|
||||
rank: number,
|
||||
api = false
|
||||
): Promise<void> {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import * as Misc from "../../utils/misc";
|
||||
import * as Strings from "../../utils/strings";
|
||||
import * as JSONData from "../../utils/json-data";
|
||||
import * as DB from "../../db";
|
||||
import Config from "../../config";
|
||||
import * as Notifications from "../notifications";
|
||||
|
|
@ -18,7 +17,7 @@ import { LocalStorageWithSchema } from "../../utils/local-storage-with-schema";
|
|||
import defaultResultFilters from "../../constants/default-result-filters";
|
||||
import { getAllFunboxes } from "@monkeytype/funbox";
|
||||
import { SnapshotUserTag } from "../../constants/default-snapshot";
|
||||
import { tryCatch } from "@monkeytype/util/trycatch";
|
||||
import { LanguageList } from "../../constants/languages";
|
||||
|
||||
export function mergeWithDefaultFilters(
|
||||
filters: Partial<ResultFilters>
|
||||
|
|
@ -746,107 +745,68 @@ export async function appendButtons(
|
|||
): Promise<void> {
|
||||
selectChangeCallbackFn = selectChangeCallback;
|
||||
|
||||
const { data: languageList, error } = await tryCatch(
|
||||
JSONData.getLanguageList()
|
||||
);
|
||||
|
||||
if (error) {
|
||||
console.error(
|
||||
Misc.createErrorMessage(error, "Failed to append language buttons")
|
||||
);
|
||||
}
|
||||
|
||||
if (languageList) {
|
||||
let html = "";
|
||||
|
||||
html +=
|
||||
"<select class='languageSelect' group='language' placeholder='select a language' multiple>";
|
||||
|
||||
html += "<option value='all'>all</option>";
|
||||
|
||||
for (const language of languageList) {
|
||||
html += `<option value="${language}" filter="${language}">${Strings.getLanguageDisplayString(
|
||||
language
|
||||
)}</option>`;
|
||||
}
|
||||
|
||||
html += "</select>";
|
||||
|
||||
const el = document.querySelector(
|
||||
".pageAccount .content .filterButtons .buttonsAndTitle.languages .select"
|
||||
);
|
||||
if (el) {
|
||||
el.innerHTML = html;
|
||||
groupSelects["language"] = new SlimSelect({
|
||||
select: el.querySelector(".languageSelect") as HTMLSelectElement,
|
||||
settings: {
|
||||
showSearch: true,
|
||||
placeholderText: "select a language",
|
||||
allowDeselect: true,
|
||||
closeOnSelect: false,
|
||||
},
|
||||
events: {
|
||||
beforeChange: (
|
||||
selectedOptions,
|
||||
oldSelectedOptions
|
||||
): void | boolean => {
|
||||
return selectBeforeChangeFn(
|
||||
"language",
|
||||
selectedOptions,
|
||||
oldSelectedOptions
|
||||
);
|
||||
},
|
||||
beforeOpen: (): void => {
|
||||
adjustScrollposition("language");
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let html = "";
|
||||
|
||||
html +=
|
||||
"<select class='funboxSelect' group='funbox' placeholder='select a funbox' multiple>";
|
||||
|
||||
html += "<option value='all'>all</option>";
|
||||
html += "<option value='none'>no funbox</option>";
|
||||
|
||||
for (const funbox of getAllFunboxes()) {
|
||||
html += `<option value="${funbox.name}" filter="${
|
||||
funbox.name
|
||||
}">${funbox.name.replace(/_/g, " ")}</option>`;
|
||||
}
|
||||
|
||||
html += "</select>";
|
||||
|
||||
const el = document.querySelector(
|
||||
".pageAccount .content .filterButtons .buttonsAndTitle.funbox .select"
|
||||
);
|
||||
if (el) {
|
||||
el.innerHTML = html;
|
||||
groupSelects["funbox"] = new SlimSelect({
|
||||
select: el.querySelector(".funboxSelect") as HTMLSelectElement,
|
||||
settings: {
|
||||
showSearch: true,
|
||||
placeholderText: "select a funbox",
|
||||
allowDeselect: true,
|
||||
closeOnSelect: false,
|
||||
groupSelects["language"] = new SlimSelect({
|
||||
select:
|
||||
".pageAccount .content .filterButtons .buttonsAndTitle.languages .select .languageSelect",
|
||||
data: [
|
||||
{ value: "all", text: "all" },
|
||||
...LanguageList.map((language) => ({
|
||||
value: language,
|
||||
text: Strings.getLanguageDisplayString(language),
|
||||
filter: language,
|
||||
})),
|
||||
],
|
||||
settings: {
|
||||
showSearch: true,
|
||||
placeholderText: "select a language",
|
||||
allowDeselect: true,
|
||||
closeOnSelect: false,
|
||||
},
|
||||
events: {
|
||||
beforeChange: (selectedOptions, oldSelectedOptions): void | boolean => {
|
||||
return selectBeforeChangeFn(
|
||||
"language",
|
||||
selectedOptions,
|
||||
oldSelectedOptions
|
||||
);
|
||||
},
|
||||
events: {
|
||||
beforeChange: (selectedOptions, oldSelectedOptions): void | boolean => {
|
||||
return selectBeforeChangeFn(
|
||||
"funbox",
|
||||
selectedOptions,
|
||||
oldSelectedOptions
|
||||
);
|
||||
},
|
||||
beforeOpen: (): void => {
|
||||
adjustScrollposition("funbox");
|
||||
},
|
||||
beforeOpen: (): void => {
|
||||
adjustScrollposition("language");
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
groupSelects["funbox"] = new SlimSelect({
|
||||
select:
|
||||
".pageAccount .content .filterButtons .buttonsAndTitle.funbox .select .funboxSelect",
|
||||
data: [
|
||||
{ value: "all", text: "all" },
|
||||
{ value: "none", text: "no funbox" },
|
||||
...getAllFunboxes().map((funbox) => ({
|
||||
value: funbox.name,
|
||||
text: funbox.name.replace(/_/g, " "),
|
||||
filter: funbox.name,
|
||||
})),
|
||||
],
|
||||
settings: {
|
||||
showSearch: true,
|
||||
placeholderText: "select a funbox",
|
||||
allowDeselect: true,
|
||||
closeOnSelect: false,
|
||||
},
|
||||
events: {
|
||||
beforeChange: (selectedOptions, oldSelectedOptions): void | boolean => {
|
||||
return selectBeforeChangeFn(
|
||||
"funbox",
|
||||
selectedOptions,
|
||||
oldSelectedOptions
|
||||
);
|
||||
},
|
||||
beforeOpen: (): void => {
|
||||
adjustScrollposition("funbox");
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const snapshot = DB.getSnapshot();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { Language } from "@monkeytype/contracts/schemas/languages";
|
||||
import Ape from "../ape";
|
||||
import { Quote } from "../controllers/quotes-controller";
|
||||
import * as DB from "../db";
|
||||
|
|
@ -12,7 +13,7 @@ type QuoteStats = {
|
|||
ratings?: number;
|
||||
totalRating?: number;
|
||||
quoteId?: number;
|
||||
language?: string;
|
||||
language?: Language;
|
||||
};
|
||||
|
||||
let quoteStats: QuoteStats | null | Record<string, never> = null;
|
||||
|
|
|
|||
|
|
@ -263,10 +263,10 @@ export async function show(showOptions?: ShowOptions): Promise<void> {
|
|||
$("#quoteSearchModal .toggleFavorites").removeClass("hidden");
|
||||
}
|
||||
|
||||
const quoteMod = DB.getSnapshot()?.quoteMod;
|
||||
const isQuoteMod =
|
||||
DB.getSnapshot()?.quoteMod !== undefined &&
|
||||
(DB.getSnapshot()?.quoteMod === true ||
|
||||
DB.getSnapshot()?.quoteMod !== "");
|
||||
quoteMod !== undefined &&
|
||||
(quoteMod === true || (quoteMod as string) !== "");
|
||||
|
||||
if (isQuoteMod) {
|
||||
$("#quoteSearchModal .goToQuoteApprove").removeClass("hidden");
|
||||
|
|
@ -348,7 +348,7 @@ const searchForQuotes = debounce(250, (): void => {
|
|||
async function toggleFavoriteForQuote(quoteId: string): Promise<void> {
|
||||
const quoteLang = Config.language;
|
||||
|
||||
if (quoteLang === "" || quoteId === "") {
|
||||
if (quoteLang === undefined || quoteId === "") {
|
||||
Notifications.add("Could not get quote stats!", -1);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,20 +3,21 @@ import * as Loader from "../elements/loader";
|
|||
import * as Notifications from "../elements/notifications";
|
||||
import * as CaptchaController from "../controllers/captcha-controller";
|
||||
import * as Strings from "../utils/strings";
|
||||
import * as JSONData from "../utils/json-data";
|
||||
import Config from "../config";
|
||||
import SlimSelect from "slim-select";
|
||||
import AnimatedModal, { ShowOptions } from "../utils/animated-modal";
|
||||
import { CharacterCounter } from "../elements/character-counter";
|
||||
import { Language } from "@monkeytype/contracts/schemas/languages";
|
||||
import { LanguageGroupNames } from "../constants/languages";
|
||||
|
||||
let dropdownReady = false;
|
||||
async function initDropdown(): Promise<void> {
|
||||
if (dropdownReady) return;
|
||||
const languageGroups = await JSONData.getLanguageGroups();
|
||||
for (const group of languageGroups) {
|
||||
if (group.name === "swiss_german") continue;
|
||||
|
||||
for (const group of LanguageGroupNames) {
|
||||
if (group === "swiss_german") continue;
|
||||
$("#quoteSubmitModal .newQuoteLanguage").append(
|
||||
`<option value="${group.name}">${group.name.replace(/_/g, " ")}</option>`
|
||||
`<option value="${group}">${group.replace(/_/g, " ")}</option>`
|
||||
);
|
||||
}
|
||||
dropdownReady = true;
|
||||
|
|
@ -27,7 +28,7 @@ let select: SlimSelect | undefined = undefined;
|
|||
async function submitQuote(): Promise<void> {
|
||||
const text = $("#quoteSubmitModal .newQuoteText").val() as string;
|
||||
const source = $("#quoteSubmitModal .newQuoteSource").val() as string;
|
||||
const language = $("#quoteSubmitModal .newQuoteLanguage").val() as string;
|
||||
const language = $("#quoteSubmitModal .newQuoteLanguage").val() as Language;
|
||||
const captcha = CaptchaController.getResponse("submitQuote");
|
||||
|
||||
if (!text || !source || !language) {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ import AnimatedModal, {
|
|||
} from "../utils/animated-modal";
|
||||
import { LayoutsList } from "../constants/layouts";
|
||||
import { tryCatch } from "@monkeytype/util/trycatch";
|
||||
import { LanguageList } from "../constants/languages";
|
||||
import { Language } from "@monkeytype/contracts/schemas/languages";
|
||||
|
||||
type FilterPreset = {
|
||||
display: string;
|
||||
|
|
@ -102,20 +104,6 @@ async function initSelectOptions(): Promise<void> {
|
|||
$("#wordFilterModal .layoutInput").empty();
|
||||
$("wordFilterModal .presetInput").empty();
|
||||
|
||||
const { data: LanguageList, error } = await tryCatch(
|
||||
JSONData.getLanguageList()
|
||||
);
|
||||
|
||||
if (error) {
|
||||
console.error(
|
||||
Misc.createErrorMessage(
|
||||
error,
|
||||
"Failed to initialise word filter popup language list"
|
||||
)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
LanguageList.forEach((language) => {
|
||||
const prettyLang = language.replace(/_/gi, " ");
|
||||
$("#wordFilterModal .languageInput").append(`
|
||||
|
|
@ -175,7 +163,7 @@ function hide(hideOptions?: HideOptions<OutgoingData>): void {
|
|||
});
|
||||
}
|
||||
|
||||
async function filter(language: string): Promise<string[]> {
|
||||
async function filter(language: Language): Promise<string[]> {
|
||||
let filterin = $("#wordFilterModal .wordIncludeInput").val() as string;
|
||||
filterin = Misc.escapeRegExp(filterin?.trim());
|
||||
filterin = filterin.replace(/\s+/gi, "|");
|
||||
|
|
@ -226,7 +214,7 @@ async function filter(language: string): Promise<string[]> {
|
|||
}
|
||||
|
||||
async function apply(set: boolean): Promise<void> {
|
||||
const language = $("#wordFilterModal .languageInput").val() as string;
|
||||
const language = $("#wordFilterModal .languageInput").val() as Language;
|
||||
const filteredWords = await filter(language);
|
||||
|
||||
if (filteredWords.length === 0) {
|
||||
|
|
|
|||
|
|
@ -373,13 +373,11 @@ async function fillContent(): Promise<void> {
|
|||
}
|
||||
}
|
||||
|
||||
let langFilter = ResultFilters.getFilter(
|
||||
"language",
|
||||
result.language ?? "english"
|
||||
);
|
||||
let langFilter = ResultFilters.getFilter("language", result.language);
|
||||
|
||||
if (
|
||||
result.language === "english_expanded" &&
|
||||
//legacy value for english_1k
|
||||
(result.language as string) === "english_expanded" &&
|
||||
ResultFilters.getFilter("language", "english_1k")
|
||||
) {
|
||||
langFilter = true;
|
||||
|
|
|
|||
|
|
@ -42,6 +42,10 @@ import { UTCDateMini } from "@date-fns/utc";
|
|||
import * as ConfigEvent from "../observables/config-event";
|
||||
import * as ActivePage from "../states/active-page";
|
||||
import { PaginationQuery } from "@monkeytype/contracts/leaderboards";
|
||||
import {
|
||||
Language,
|
||||
LanguageSchema,
|
||||
} from "@monkeytype/contracts/schemas/languages";
|
||||
|
||||
const LeaderboardTypeSchema = z.enum(["allTime", "weekly", "daily"]);
|
||||
type LeaderboardType = z.infer<typeof LeaderboardTypeSchema>;
|
||||
|
|
@ -71,7 +75,7 @@ type DailyState = {
|
|||
mode2: "15" | "60";
|
||||
yesterday: boolean;
|
||||
minWpm: number;
|
||||
language: string;
|
||||
language: Language;
|
||||
data: LeaderboardEntry[] | null;
|
||||
count: number;
|
||||
userData: LeaderboardEntry | null;
|
||||
|
|
@ -108,7 +112,7 @@ const state = {
|
|||
const SelectorSchema = z.object({
|
||||
type: LeaderboardTypeSchema,
|
||||
mode2: z.enum(["15", "60"]).optional(),
|
||||
language: z.string().optional(),
|
||||
language: LanguageSchema.optional(),
|
||||
yesterday: z.boolean().optional(),
|
||||
lastWeek: z.boolean().optional(),
|
||||
});
|
||||
|
|
@ -1255,7 +1259,7 @@ $(".page.pageLeaderboards .buttonGroup.secondary").on(
|
|||
"button",
|
||||
function () {
|
||||
const mode = $(this).attr("data-mode") as "15" | "60" | undefined;
|
||||
const language = $(this).data("language") as string;
|
||||
const language = $(this).data("language") as Language;
|
||||
if (
|
||||
mode !== undefined &&
|
||||
(state.type === "allTime" || state.type === "daily")
|
||||
|
|
|
|||
|
|
@ -35,6 +35,8 @@ import { tryCatch } from "@monkeytype/util/trycatch";
|
|||
import { Theme, ThemesList } from "../constants/themes";
|
||||
import { areSortedArraysEqual, areUnsortedArraysEqual } from "../utils/arrays";
|
||||
import { LayoutName } from "@monkeytype/contracts/schemas/layouts";
|
||||
import { LanguageGroupNames, LanguageGroups } from "../constants/languages";
|
||||
import { Language } from "@monkeytype/contracts/schemas/languages";
|
||||
|
||||
let settingsInitialized = false;
|
||||
|
||||
|
|
@ -438,25 +440,9 @@ async function fillSettingsPage(): Promise<void> {
|
|||
return;
|
||||
}
|
||||
// Language Selection Combobox
|
||||
|
||||
const { data: languageGroups, error: getLanguageGroupsError } =
|
||||
await tryCatch(JSONData.getLanguageGroups());
|
||||
|
||||
if (getLanguageGroupsError) {
|
||||
console.error(
|
||||
Misc.createErrorMessage(
|
||||
getLanguageGroupsError,
|
||||
"Failed to initialize settings language picker"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
new SlimSelect({
|
||||
select: ".pageSettings .section[data-config-name='language'] select",
|
||||
data: getLanguageDropdownData(
|
||||
languageGroups ?? [],
|
||||
(language) => language === Config.language
|
||||
),
|
||||
data: getLanguageDropdownData((language) => language === Config.language),
|
||||
settings: {
|
||||
searchPlaceholder: "search",
|
||||
},
|
||||
|
|
@ -612,12 +598,12 @@ async function fillSettingsPage(): Promise<void> {
|
|||
|
||||
customPolyglotSelect = new SlimSelect({
|
||||
select: ".pageSettings .section[data-config-name='customPolyglot'] select",
|
||||
data: getLanguageDropdownData(languageGroups ?? [], (language) =>
|
||||
data: getLanguageDropdownData((language) =>
|
||||
Config.customPolyglot.includes(language)
|
||||
),
|
||||
events: {
|
||||
afterChange: (newVal): void => {
|
||||
const customPolyglot = newVal.map((it) => it.value);
|
||||
const customPolyglot = newVal.map((it) => it.value) as Language[];
|
||||
//checking equal without order, because customPolyglot is not ordered
|
||||
if (!areUnsortedArraysEqual(customPolyglot, Config.customPolyglot)) {
|
||||
void UpdateConfig.setCustomPolyglot(customPolyglot);
|
||||
|
|
@ -1309,14 +1295,13 @@ export function setEventDisabled(value: boolean): void {
|
|||
}
|
||||
|
||||
function getLanguageDropdownData(
|
||||
languageGroups: JSONData.LanguageGroup[],
|
||||
isActive: (val: string) => boolean
|
||||
isActive: (val: Language) => boolean
|
||||
): DataArrayPartial {
|
||||
return languageGroups.map(
|
||||
return LanguageGroupNames.map(
|
||||
(group) =>
|
||||
({
|
||||
label: group.name,
|
||||
options: group.languages.map((language) => ({
|
||||
label: group,
|
||||
options: LanguageGroups[group]?.map((language) => ({
|
||||
text: Strings.getLanguageDisplayString(language),
|
||||
value: language,
|
||||
selected: isActive(language),
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ import {
|
|||
KeymapLayout,
|
||||
Layout,
|
||||
} from "@monkeytype/contracts/schemas/configs";
|
||||
|
||||
import { Language } from "@monkeytype/contracts/schemas/languages";
|
||||
export type FunboxFunctions = {
|
||||
getWord?: (wordset?: Wordset, wordIndex?: number) => string;
|
||||
punctuateWord?: (word: string) => string;
|
||||
|
|
@ -38,7 +38,7 @@ export type FunboxFunctions = {
|
|||
clearGlobal?: () => void;
|
||||
rememberSettings?: () => void;
|
||||
toggleScript?: (params: string[]) => void;
|
||||
pullSection?: (language?: string) => Promise<Section | false>;
|
||||
pullSection?: (language?: Language) => Promise<Section | false>;
|
||||
handleSpace?: () => void;
|
||||
handleChar?: (char: string) => string;
|
||||
isCharCorrect?: (char: string, originalChar: string) => boolean;
|
||||
|
|
@ -509,7 +509,7 @@ const list: Partial<Record<FunboxName, FunboxFunctions>> = {
|
|||
},
|
||||
},
|
||||
wikipedia: {
|
||||
async pullSection(lang?: string): Promise<JSONData.Section | false> {
|
||||
async pullSection(lang?: Language): Promise<JSONData.Section | false> {
|
||||
return getSection((lang ?? "") || "english");
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -40,13 +40,14 @@ import { CompletedEvent } from "@monkeytype/contracts/schemas/results";
|
|||
import { getActiveFunboxes, isFunboxActiveWithProperty } from "./funbox/list";
|
||||
import { getFunbox } from "@monkeytype/funbox";
|
||||
import { SnapshotUserTag } from "../constants/default-snapshot";
|
||||
import { Language } from "@monkeytype/contracts/schemas/languages";
|
||||
|
||||
let result: CompletedEvent;
|
||||
let maxChartVal: number;
|
||||
|
||||
let useUnsmoothedRaw = false;
|
||||
|
||||
let quoteLang = "";
|
||||
let quoteLang: Language | undefined;
|
||||
let quoteId = "";
|
||||
|
||||
export function toggleUnsmoothedRaw(): void {
|
||||
|
|
@ -816,7 +817,7 @@ function updateQuoteFavorite(randomQuote: Quote | null): void {
|
|||
return;
|
||||
}
|
||||
|
||||
quoteLang = Config.mode === "quote" ? randomQuote.language : "";
|
||||
quoteLang = Config.mode === "quote" ? randomQuote.language : undefined;
|
||||
quoteId = Config.mode === "quote" ? randomQuote.id.toString() : "";
|
||||
|
||||
const userFav = QuotesController.isQuoteFavorite(randomQuote);
|
||||
|
|
@ -1041,7 +1042,7 @@ export function updateTagsAfterEdit(
|
|||
}
|
||||
|
||||
$(".pageTest #favoriteQuoteButton").on("click", async () => {
|
||||
if (quoteLang === "" || quoteId === "") {
|
||||
if (quoteLang === undefined || quoteId === "") {
|
||||
Notifications.add("Could not get quote stats!", -1);
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,10 +4,11 @@ import * as Strings from "../utils/strings";
|
|||
import * as JSONData from "../utils/json-data";
|
||||
import { z } from "zod";
|
||||
import { parseWithSchema as parseJsonWithSchema } from "@monkeytype/util/json";
|
||||
import { tryCatch } from "@monkeytype/util/trycatch";
|
||||
import { getGroupForLanguage, LanguageGroupName } from "../constants/languages";
|
||||
import { Language } from "@monkeytype/contracts/schemas/languages";
|
||||
|
||||
export async function getTLD(
|
||||
languageGroup: JSONData.LanguageGroup
|
||||
languageGroup: LanguageGroupName
|
||||
): Promise<
|
||||
| "en"
|
||||
| "es"
|
||||
|
|
@ -65,7 +66,7 @@ export async function getTLD(
|
|||
| "eu"
|
||||
> {
|
||||
// language group to tld
|
||||
switch (languageGroup.name) {
|
||||
switch (languageGroup) {
|
||||
case "english":
|
||||
return "en";
|
||||
|
||||
|
|
@ -256,23 +257,17 @@ const SectionSchema = z.object({
|
|||
}),
|
||||
});
|
||||
|
||||
export async function getSection(language: string): Promise<JSONData.Section> {
|
||||
export async function getSection(
|
||||
language: Language
|
||||
): Promise<JSONData.Section> {
|
||||
// console.log("Getting section");
|
||||
Loader.show();
|
||||
|
||||
// get TLD for wikipedia according to language group
|
||||
let urlTLD = "en";
|
||||
|
||||
const { data: currentLanguageGroup, error } = await tryCatch(
|
||||
JSONData.getCurrentGroup(language)
|
||||
);
|
||||
if (error) {
|
||||
console.error(
|
||||
Misc.createErrorMessage(error, "Failed to find current language group")
|
||||
);
|
||||
}
|
||||
|
||||
if (currentLanguageGroup !== null && currentLanguageGroup !== undefined) {
|
||||
const currentLanguageGroup = getGroupForLanguage(language);
|
||||
if (currentLanguageGroup !== undefined) {
|
||||
urlTLD = await getTLD(currentLanguageGroup);
|
||||
}
|
||||
|
||||
|
|
@ -293,7 +288,6 @@ export async function getSection(language: string): Promise<JSONData.Section> {
|
|||
Loader.hide();
|
||||
rej(randomPostReq.status);
|
||||
}
|
||||
|
||||
const sectionURL = `https://${urlTLD}.wikipedia.org/w/api.php?action=query&format=json&pageids=${pageid}&prop=extracts&exintro=true&origin=*`;
|
||||
|
||||
const sectionReq = new XMLHttpRequest();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { FunboxName } from "@monkeytype/contracts/schemas/configs";
|
||||
import { Language } from "@monkeytype/contracts/schemas/languages";
|
||||
import { Accents } from "../test/lazy-mode";
|
||||
|
||||
/**
|
||||
|
|
@ -91,33 +92,8 @@ export async function getLayout(layoutName: string): Promise<Layout> {
|
|||
return await cachedFetchJson<Layout>(`/layouts/${layoutName}.json`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the list of languages from the server.
|
||||
* @returns A promise that resolves to the list of languages.
|
||||
*/
|
||||
export async function getLanguageList(): Promise<string[]> {
|
||||
const languageList = await cachedFetchJson<string[]>("/languages/_list.json");
|
||||
return languageList;
|
||||
}
|
||||
|
||||
export type LanguageGroup = {
|
||||
name: string;
|
||||
languages: string[];
|
||||
};
|
||||
|
||||
/**
|
||||
* Fetches the list of language groups from the server.
|
||||
* @returns A promise that resolves to the list of language groups.
|
||||
*/
|
||||
export async function getLanguageGroups(): Promise<LanguageGroup[]> {
|
||||
const languageGroupList = await cachedFetchJson<LanguageGroup[]>(
|
||||
"/languages/_groups.json"
|
||||
);
|
||||
return languageGroupList;
|
||||
}
|
||||
|
||||
export type LanguageObject = {
|
||||
name: string;
|
||||
name: Language;
|
||||
rightToLeft: boolean;
|
||||
noLazyMode?: boolean;
|
||||
ligatures?: boolean;
|
||||
|
|
@ -135,7 +111,8 @@ let currentLanguage: LanguageObject;
|
|||
* @param lang The language code.
|
||||
* @returns A promise that resolves to the language object.
|
||||
*/
|
||||
export async function getLanguage(lang: string): Promise<LanguageObject> {
|
||||
export async function getLanguage(lang: Language): Promise<LanguageObject> {
|
||||
// try {
|
||||
if (currentLanguage === undefined || currentLanguage.name !== lang) {
|
||||
currentLanguage = await cachedFetchJson<LanguageObject>(
|
||||
`/languages/${lang}.json`
|
||||
|
|
@ -145,7 +122,7 @@ export async function getLanguage(lang: string): Promise<LanguageObject> {
|
|||
}
|
||||
|
||||
export async function checkIfLanguageSupportsZipf(
|
||||
language: string
|
||||
language: Language
|
||||
): Promise<"yes" | "no" | "unknown"> {
|
||||
const lang = await getLanguage(language);
|
||||
if (lang.orderedByFrequency === true) return "yes";
|
||||
|
|
@ -159,31 +136,11 @@ export async function checkIfLanguageSupportsZipf(
|
|||
* @returns A promise that resolves to the current language object.
|
||||
*/
|
||||
export async function getCurrentLanguage(
|
||||
languageName: string
|
||||
languageName: Language
|
||||
): Promise<LanguageObject> {
|
||||
return await getLanguage(languageName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the language group for a given language.
|
||||
* @param language The language code.
|
||||
* @returns A promise that resolves to the language group.
|
||||
*/
|
||||
export async function getCurrentGroup(
|
||||
language: string
|
||||
): Promise<LanguageGroup | undefined> {
|
||||
let retgroup: LanguageGroup | undefined;
|
||||
const groups = await getLanguageGroups();
|
||||
groups.forEach((group) => {
|
||||
if (retgroup === undefined) {
|
||||
if (group.languages.includes(language)) {
|
||||
retgroup = group;
|
||||
}
|
||||
}
|
||||
});
|
||||
return retgroup;
|
||||
}
|
||||
|
||||
export class Section {
|
||||
public title: string;
|
||||
public author: string;
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { Language } from "@monkeytype/contracts/schemas/languages";
|
||||
|
||||
/**
|
||||
* Removes accents from a string.
|
||||
* https://ricardometring.com/javascript-replace-special-characters
|
||||
|
|
@ -101,7 +103,7 @@ export function splitByAndKeep(text: string, delimiters: string[]): string[] {
|
|||
* @returns A display string for the language.
|
||||
*/
|
||||
export function getLanguageDisplayString(
|
||||
language: string,
|
||||
language: Language,
|
||||
noSizeString = false
|
||||
): string {
|
||||
let out = "";
|
||||
|
|
@ -118,8 +120,8 @@ export function getLanguageDisplayString(
|
|||
* @param language The language string.
|
||||
* @returns The language string with the size indicator removed.
|
||||
*/
|
||||
export function removeLanguageSize(language: string): string {
|
||||
return language.replace(/_\d*k$/g, "");
|
||||
export function removeLanguageSize(language: Language): Language {
|
||||
return language.replace(/_\d*k$/g, "") as Language;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ import {
|
|||
import { z } from "zod";
|
||||
import { parseWithSchema as parseJsonWithSchema } from "@monkeytype/util/json";
|
||||
import { tryCatchSync } from "@monkeytype/util/trycatch";
|
||||
import { Language } from "@monkeytype/contracts/schemas/languages";
|
||||
|
||||
export async function linkDiscord(hashOverride: string): Promise<void> {
|
||||
if (!hashOverride) return;
|
||||
|
|
@ -239,7 +240,7 @@ export function loadTestSettingsFromUrl(getOverride?: string): void {
|
|||
}
|
||||
|
||||
if (de[5] !== null) {
|
||||
UpdateConfig.setLanguage(de[5], true);
|
||||
UpdateConfig.setLanguage(de[5] as Language, true);
|
||||
applied["language"] = de[5];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,682 +0,0 @@
|
|||
[
|
||||
{
|
||||
"name": "english",
|
||||
"languages": [
|
||||
"english",
|
||||
"english_1k",
|
||||
"english_5k",
|
||||
"english_10k",
|
||||
"english_25k",
|
||||
"english_450k",
|
||||
"english_commonly_misspelled",
|
||||
"english_contractions",
|
||||
"english_doubleletter",
|
||||
"english_shakespearean",
|
||||
"english_old",
|
||||
"english_medical"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "spanish",
|
||||
"languages": ["spanish", "spanish_1k", "spanish_10k", "spanish_650k"]
|
||||
},
|
||||
{
|
||||
"name": "french",
|
||||
"languages": [
|
||||
"french",
|
||||
"french_1k",
|
||||
"french_2k",
|
||||
"french_10k",
|
||||
"french_600k",
|
||||
"french_bitoduc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "german",
|
||||
"languages": ["german", "german_1k", "german_10k", "german_250k"]
|
||||
},
|
||||
{
|
||||
"name": "swiss_german",
|
||||
"languages": ["swiss_german", "swiss_german_1k", "swiss_german_2k"]
|
||||
},
|
||||
{
|
||||
"name": "portuguese",
|
||||
"languages": [
|
||||
"portuguese",
|
||||
"portuguese_1k",
|
||||
"portuguese_3k",
|
||||
"portuguese_5k",
|
||||
"portuguese_320k",
|
||||
"portuguese_550k",
|
||||
"portuguese_acentos_e_cedilha"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "arabic",
|
||||
"languages": ["arabic", "arabic_10k"]
|
||||
},
|
||||
{
|
||||
"name": "arabic_egypt",
|
||||
"languages": ["arabic_egypt", "arabic_egypt_1k"]
|
||||
},
|
||||
{
|
||||
"name": "italian",
|
||||
"languages": [
|
||||
"italian",
|
||||
"italian_1k",
|
||||
"italian_7k",
|
||||
"italian_60k",
|
||||
"italian_280k"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "friulian",
|
||||
"languages": ["friulian"]
|
||||
},
|
||||
{
|
||||
"name": "latin",
|
||||
"languages": ["latin"]
|
||||
},
|
||||
{
|
||||
"name": "afrikaans",
|
||||
"languages": ["afrikaans", "afrikaans_1k", "afrikaans_10k"]
|
||||
},
|
||||
{
|
||||
"name": "mongolian",
|
||||
"languages": ["mongolian", "mongolian_10k"]
|
||||
},
|
||||
{
|
||||
"name": "korean",
|
||||
"languages": ["korean", "korean_1k", "korean_5k"]
|
||||
},
|
||||
{
|
||||
"name": "khmer",
|
||||
"languages": ["khmer"]
|
||||
},
|
||||
{
|
||||
"name": "marathi",
|
||||
"languages": ["marathi"]
|
||||
},
|
||||
{
|
||||
"name": "chinese",
|
||||
"languages": [
|
||||
"chinese_traditional",
|
||||
"chinese_simplified",
|
||||
"chinese_simplified_1k",
|
||||
"chinese_simplified_5k",
|
||||
"chinese_simplified_10k",
|
||||
"chinese_simplified_50k"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "russian",
|
||||
"languages": [
|
||||
"russian",
|
||||
"russian_1k",
|
||||
"russian_5k",
|
||||
"russian_10k",
|
||||
"russian_25k",
|
||||
"russian_50k",
|
||||
"russian_375k",
|
||||
"russian_contractions",
|
||||
"russian_contractions_1k",
|
||||
"russian_abbreviations"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "polish",
|
||||
"languages": [
|
||||
"polish",
|
||||
"polish_2k",
|
||||
"polish_5k",
|
||||
"polish_10k",
|
||||
"polish_20k",
|
||||
"polish_40k",
|
||||
"polish_200k"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "czech",
|
||||
"languages": ["czech", "czech_1k", "czech_10k"]
|
||||
},
|
||||
{
|
||||
"name": "slovak",
|
||||
"languages": ["slovak", "slovak_1k", "slovak_10k"]
|
||||
},
|
||||
{
|
||||
"name": "ukrainian",
|
||||
"languages": [
|
||||
"ukrainian",
|
||||
"ukrainian_1k",
|
||||
"ukrainian_10k",
|
||||
"ukrainian_50k",
|
||||
"ukrainian_endings"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "ukrainian_latynka",
|
||||
"languages": [
|
||||
"ukrainian_latynka",
|
||||
"ukrainian_latynka_1k",
|
||||
"ukrainian_latynka_10k",
|
||||
"ukrainian_latynka_50k",
|
||||
"ukrainian_latynka_endings"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "lithuanian",
|
||||
"languages": ["lithuanian", "lithuanian_1k", "lithuanian_3k"]
|
||||
},
|
||||
{
|
||||
"name": "indonesian",
|
||||
"languages": ["indonesian", "indonesian_1k", "indonesian_10k"]
|
||||
},
|
||||
{
|
||||
"name": "kurdish_central",
|
||||
"languages": ["kurdish_central", "kurdish_central_2k", "kurdish_central_4k"]
|
||||
},
|
||||
{
|
||||
"name": "greek",
|
||||
"languages": ["greek", "greek_1k", "greek_5k", "greek_10k", "greek_25k"]
|
||||
},
|
||||
{
|
||||
"name": "greeklish",
|
||||
"languages": [
|
||||
"greeklish",
|
||||
"greeklish_1k",
|
||||
"greeklish_5k",
|
||||
"greeklish_10k",
|
||||
"greeklish_25k"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "turkish",
|
||||
"languages": ["turkish", "turkish_1k", "turkish_5k"]
|
||||
},
|
||||
{
|
||||
"name": "irish",
|
||||
"languages": ["irish"]
|
||||
},
|
||||
{
|
||||
"name": "galician",
|
||||
"languages": ["galician"]
|
||||
},
|
||||
{
|
||||
"name": "thai",
|
||||
"languages": ["thai", "thai_20k"]
|
||||
},
|
||||
{
|
||||
"name": "tamil",
|
||||
"languages": ["tamil", "tamil_1k", "tanglish", "tamil_old"]
|
||||
},
|
||||
{
|
||||
"name": "kannada",
|
||||
"languages": ["kannada"]
|
||||
},
|
||||
{
|
||||
"name": "telugu",
|
||||
"languages": ["telugu", "telugu_1k"]
|
||||
},
|
||||
{
|
||||
"name": "slovenian",
|
||||
"languages": ["slovenian", "slovenian_1k", "slovenian_5k"]
|
||||
},
|
||||
{
|
||||
"name": "croatian",
|
||||
"languages": ["croatian", "croatian_1k"]
|
||||
},
|
||||
{
|
||||
"name": "dutch",
|
||||
"languages": ["dutch", "dutch_1k", "dutch_10k"]
|
||||
},
|
||||
{
|
||||
"name": "filipino",
|
||||
"languages": ["filipino", "filipino_1k"]
|
||||
},
|
||||
{
|
||||
"name": "danish",
|
||||
"languages": ["danish", "danish_1k", "danish_10k"]
|
||||
},
|
||||
{
|
||||
"name": "hungarian",
|
||||
"languages": ["hungarian", "hungarian_2k"]
|
||||
},
|
||||
{
|
||||
"name": "norwegian_bokmal",
|
||||
"languages": [
|
||||
"norwegian_bokmal",
|
||||
"norwegian_bokmal_1k",
|
||||
"norwegian_bokmal_5k",
|
||||
"norwegian_bokmal_10k",
|
||||
"norwegian_bokmal_150k",
|
||||
"norwegian_bokmal_600k"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "norwegian_nynorsk",
|
||||
"languages": [
|
||||
"norwegian_nynorsk",
|
||||
"norwegian_nynorsk_1k",
|
||||
"norwegian_nynorsk_5k",
|
||||
"norwegian_nynorsk_10k",
|
||||
"norwegian_nynorsk_100k",
|
||||
"norwegian_nynorsk_400k"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "hebrew",
|
||||
"languages": ["hebrew", "hebrew_1k", "hebrew_5k", "hebrew_10k"]
|
||||
},
|
||||
{
|
||||
"name": "icelandic",
|
||||
"languages": ["icelandic_1k"]
|
||||
},
|
||||
{
|
||||
"name": "malagasy",
|
||||
"languages": ["malagasy", "malagasy_1k"]
|
||||
},
|
||||
{
|
||||
"name": "malay",
|
||||
"languages": ["malay", "malay_1k"]
|
||||
},
|
||||
{
|
||||
"name": "romanian",
|
||||
"languages": [
|
||||
"romanian",
|
||||
"romanian_1k",
|
||||
"romanian_5k",
|
||||
"romanian_10k",
|
||||
"romanian_25k",
|
||||
"romanian_50k",
|
||||
"romanian_100k",
|
||||
"romanian_200k"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "finnish",
|
||||
"languages": ["finnish", "finnish_1k", "finnish_10k"]
|
||||
},
|
||||
{
|
||||
"name": "estonian",
|
||||
"languages": ["estonian", "estonian_1k", "estonian_5k", "estonian_10k"]
|
||||
},
|
||||
{
|
||||
"name": "udmurt",
|
||||
"languages": ["udmurt"]
|
||||
},
|
||||
{
|
||||
"name": "welsh",
|
||||
"languages": ["welsh", "welsh_1k"]
|
||||
},
|
||||
{
|
||||
"name": "persian",
|
||||
"languages": [
|
||||
"persian",
|
||||
"persian_1k",
|
||||
"persian_5k",
|
||||
"persian_20k",
|
||||
"persian_romanized"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "kazakh",
|
||||
"languages": ["kazakh", "kazakh_1k"]
|
||||
},
|
||||
{
|
||||
"name": "vietnamese",
|
||||
"languages": ["vietnamese", "vietnamese_1k", "vietnamese_5k"]
|
||||
},
|
||||
{
|
||||
"name": "jyutping",
|
||||
"languages": ["jyutping"]
|
||||
},
|
||||
{
|
||||
"name": "pinyin",
|
||||
"languages": ["pinyin", "pinyin_1k", "pinyin_10k"]
|
||||
},
|
||||
{
|
||||
"name": "hausa",
|
||||
"languages": ["hausa", "hausa_1k"]
|
||||
},
|
||||
{
|
||||
"name": "swedish",
|
||||
"languages": ["swedish", "swedish_1k", "swedish_diacritics"]
|
||||
},
|
||||
{
|
||||
"name": "serbian",
|
||||
"languages": [
|
||||
"serbian",
|
||||
"serbian_latin",
|
||||
"serbian_10k",
|
||||
"serbian_latin_10k"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "georgian",
|
||||
"languages": ["georgian"]
|
||||
},
|
||||
{
|
||||
"name": "yoruba",
|
||||
"languages": ["yoruba_1k"]
|
||||
},
|
||||
{
|
||||
"name": "swahili",
|
||||
"languages": ["swahili_1k"]
|
||||
},
|
||||
{
|
||||
"name": "maori",
|
||||
"languages": ["maori_1k"]
|
||||
},
|
||||
{
|
||||
"name": "catalan",
|
||||
"languages": ["catalan", "catalan_1k"]
|
||||
},
|
||||
{
|
||||
"name": "bulgarian",
|
||||
"languages": ["bulgarian", "bulgarian_latin"]
|
||||
},
|
||||
{
|
||||
"name": "bosnian",
|
||||
"languages": ["bosnian", "bosnian_4k"]
|
||||
},
|
||||
{
|
||||
"name": "esperanto",
|
||||
"languages": [
|
||||
"esperanto",
|
||||
"esperanto_1k",
|
||||
"esperanto_10k",
|
||||
"esperanto_25k",
|
||||
"esperanto_36k",
|
||||
"esperanto_x_sistemo",
|
||||
"esperanto_x_sistemo_1k",
|
||||
"esperanto_x_sistemo_10k",
|
||||
"esperanto_x_sistemo_25k",
|
||||
"esperanto_x_sistemo_36k",
|
||||
"esperanto_h_sistemo",
|
||||
"esperanto_h_sistemo_1k",
|
||||
"esperanto_h_sistemo_10k",
|
||||
"esperanto_h_sistemo_25k",
|
||||
"esperanto_h_sistemo_36k"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "bangla",
|
||||
"languages": ["bangla", "bangla_letters", "bangla_10k"]
|
||||
},
|
||||
{
|
||||
"name": "urdu",
|
||||
"languages": ["urdu", "urdu_1k", "urdu_5k", "urdish"]
|
||||
},
|
||||
{
|
||||
"name": "albanian",
|
||||
"languages": ["albanian", "albanian_1k"]
|
||||
},
|
||||
{
|
||||
"name": "shona",
|
||||
"languages": ["shona", "shona_1k"]
|
||||
},
|
||||
{
|
||||
"name": "armenian",
|
||||
"languages": [
|
||||
"armenian",
|
||||
"armenian_1k",
|
||||
"armenian_western",
|
||||
"armenian_western_1k"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "myanmar",
|
||||
"languages": ["myanmar_burmese"]
|
||||
},
|
||||
{
|
||||
"name": "japanese",
|
||||
"languages": [
|
||||
"japanese_hiragana",
|
||||
"japanese_katakana",
|
||||
"japanese_romaji",
|
||||
"japanese_romaji_1k"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "hindi",
|
||||
"languages": ["hindi", "hindi_1k", "hinglish"]
|
||||
},
|
||||
{
|
||||
"name": "sanskrit",
|
||||
"languages": ["sanskrit", "sanskrit_roman"]
|
||||
},
|
||||
{
|
||||
"name": "gujarati",
|
||||
"languages": ["gujarati", "gujarati_1k"]
|
||||
},
|
||||
{
|
||||
"name": "nepali",
|
||||
"languages": ["nepali", "nepali_1k", "nepali_romanized"]
|
||||
},
|
||||
{
|
||||
"name": "santali",
|
||||
"languages": ["santali"]
|
||||
},
|
||||
{
|
||||
"name": "macedonian",
|
||||
"languages": [
|
||||
"macedonian",
|
||||
"macedonian_1k",
|
||||
"macedonian_10k",
|
||||
"macedonian_75k"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "uzbek",
|
||||
"languages": ["uzbek", "uzbek_1k", "uzbek_70k"]
|
||||
},
|
||||
{
|
||||
"name": "belarusian",
|
||||
"languages": [
|
||||
"belarusian",
|
||||
"belarusian_1k",
|
||||
"belarusian_5k",
|
||||
"belarusian_10k",
|
||||
"belarusian_25k",
|
||||
"belarusian_50k",
|
||||
"belarusian_100k"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "belarusian_lacinka",
|
||||
"languages": ["belarusian_lacinka", "belarusian_lacinka_1k"]
|
||||
},
|
||||
{
|
||||
"name": "tatar",
|
||||
"languages": ["tatar", "tatar_1k", "tatar_5k", "tatar_9k"]
|
||||
},
|
||||
{
|
||||
"name": "tatar_crimean",
|
||||
"languages": [
|
||||
"tatar_crimean",
|
||||
"tatar_crimean_1k",
|
||||
"tatar_crimean_5k",
|
||||
"tatar_crimean_10k",
|
||||
"tatar_crimean_15k",
|
||||
"tatar_crimean_cyrillic",
|
||||
"tatar_crimean_cyrillic_1k",
|
||||
"tatar_crimean_cyrillic_5k",
|
||||
"tatar_crimean_cyrillic_10k",
|
||||
"tatar_crimean_cyrillic_15k"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "azerbaijani",
|
||||
"languages": ["azerbaijani", "azerbaijani_1k"]
|
||||
},
|
||||
{
|
||||
"name": "malayalam",
|
||||
"languages": ["malayalam"]
|
||||
},
|
||||
{
|
||||
"name": "sinhala",
|
||||
"languages": ["sinhala"]
|
||||
},
|
||||
{
|
||||
"name": "latvian",
|
||||
"languages": ["latvian", "latvian_1k"]
|
||||
},
|
||||
{
|
||||
"name": "maltese",
|
||||
"languages": ["maltese", "maltese_1k"]
|
||||
},
|
||||
{
|
||||
"name": "toki_pona",
|
||||
"languages": ["toki_pona", "toki_pona_ku_suli", "toki_pona_ku_lili"]
|
||||
},
|
||||
{
|
||||
"name": "xhosa",
|
||||
"languages": ["xhosa", "xhosa_3k"]
|
||||
},
|
||||
{
|
||||
"name": "tibetan",
|
||||
"languages": ["tibetan", "tibetan_1k"]
|
||||
},
|
||||
{
|
||||
"name": "bashkir",
|
||||
"languages": ["bashkir"]
|
||||
},
|
||||
{
|
||||
"name": "other",
|
||||
"languages": [
|
||||
"lojban_gismu",
|
||||
"lojban_cmavo",
|
||||
"pig_latin",
|
||||
"twitch_emotes",
|
||||
"git",
|
||||
"typing_of_the_dead",
|
||||
"league_of_legends",
|
||||
"docker_file"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "amharic",
|
||||
"languages": ["amharic", "amharic_1k", "amharic_5k"]
|
||||
},
|
||||
{
|
||||
"name": "oromo",
|
||||
"languages": ["oromo", "oromo_1k", "oromo_5k"]
|
||||
},
|
||||
{
|
||||
"name": "wordle",
|
||||
"languages": ["wordle", "wordle_1k"]
|
||||
},
|
||||
{
|
||||
"name": "kyrgyz",
|
||||
"languages": ["kyrgyz", "kyrgyz_1k"]
|
||||
},
|
||||
{
|
||||
"name": "yiddish",
|
||||
"languages": ["yiddish"]
|
||||
},
|
||||
{
|
||||
"name": "frisian",
|
||||
"languages": ["frisian", "frisian_1k"]
|
||||
},
|
||||
{
|
||||
"name": "pashto",
|
||||
"languages": ["pashto"]
|
||||
},
|
||||
{
|
||||
"name": "euskera",
|
||||
"languages": ["euskera"]
|
||||
},
|
||||
{
|
||||
"name": "klingon",
|
||||
"languages": ["klingon", "klingon_1k"]
|
||||
},
|
||||
{
|
||||
"name": "quenya",
|
||||
"languages": ["quenya"]
|
||||
},
|
||||
{
|
||||
"name": "lorem_ipsum",
|
||||
"languages": ["lorem_ipsum"]
|
||||
},
|
||||
{
|
||||
"name": "occitan",
|
||||
"languages": [
|
||||
"occitan",
|
||||
"occitan_1k",
|
||||
"occitan_2k",
|
||||
"occitan_5k",
|
||||
"occitan_10k"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "kabyle",
|
||||
"languages": ["kabyle", "kabyle_1k", "kabyle_2k", "kabyle_5k", "kabyle_10k"]
|
||||
},
|
||||
{
|
||||
"name": "zulu",
|
||||
"languages": ["zulu"]
|
||||
},
|
||||
{
|
||||
"name": "code",
|
||||
"languages": [
|
||||
"code_python",
|
||||
"code_python_1k",
|
||||
"code_python_2k",
|
||||
"code_python_5k",
|
||||
"code_c",
|
||||
"code_csharp",
|
||||
"code_c++",
|
||||
"code_dart",
|
||||
"code_brainfck",
|
||||
"code_fsharp",
|
||||
"code_javascript",
|
||||
"code_javascript_1k",
|
||||
"code_javascript_react",
|
||||
"code_jule",
|
||||
"code_julia",
|
||||
"code_haskell",
|
||||
"code_html",
|
||||
"code_nim",
|
||||
"code_nix",
|
||||
"code_pascal",
|
||||
"code_java",
|
||||
"code_kotlin",
|
||||
"code_go",
|
||||
"code_rockstar",
|
||||
"code_rust",
|
||||
"code_ruby",
|
||||
"code_r",
|
||||
"code_r_2k",
|
||||
"code_swift",
|
||||
"code_scala",
|
||||
"code_bash",
|
||||
"code_powershell",
|
||||
"code_lua",
|
||||
"code_luau",
|
||||
"code_latex",
|
||||
"code_typst",
|
||||
"code_matlab",
|
||||
"code_sql",
|
||||
"code_perl",
|
||||
"code_php",
|
||||
"code_vim",
|
||||
"code_vimscript",
|
||||
"code_opencl",
|
||||
"code_visual_basic",
|
||||
"code_arduino",
|
||||
"code_systemverilog",
|
||||
"code_elixir",
|
||||
"code_zig",
|
||||
"code_gdscript",
|
||||
"code_gdscript_2",
|
||||
"code_assembly",
|
||||
"code_v",
|
||||
"code_ook",
|
||||
"code_typescript",
|
||||
"code_cobol",
|
||||
"code_common_lisp",
|
||||
"code_odin",
|
||||
"code_fortran"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
|
@ -1,402 +0,0 @@
|
|||
[
|
||||
"english"
|
||||
,"english_1k"
|
||||
,"english_5k"
|
||||
,"english_10k"
|
||||
,"english_25k"
|
||||
,"english_450k"
|
||||
,"english_commonly_misspelled"
|
||||
,"english_contractions"
|
||||
,"english_doubleletter"
|
||||
,"english_shakespearean"
|
||||
,"english_old"
|
||||
,"english_medical"
|
||||
,"spanish"
|
||||
,"spanish_1k"
|
||||
,"spanish_10k"
|
||||
,"spanish_650k"
|
||||
,"french"
|
||||
,"french_1k"
|
||||
,"french_2k"
|
||||
,"french_10k"
|
||||
,"french_600k"
|
||||
,"french_bitoduc"
|
||||
,"nepali"
|
||||
,"nepali_1k"
|
||||
,"nepali_romanized"
|
||||
,"sanskrit"
|
||||
,"sanskrit_roman"
|
||||
,"santali"
|
||||
,"azerbaijani"
|
||||
,"azerbaijani_1k"
|
||||
,"arabic"
|
||||
,"arabic_10k"
|
||||
,"arabic_egypt"
|
||||
,"arabic_egypt_1k"
|
||||
,"malagasy"
|
||||
,"malagasy_1k"
|
||||
,"malay"
|
||||
,"malay_1k"
|
||||
,"mongolian"
|
||||
,"mongolian_10k"
|
||||
,"kannada"
|
||||
,"korean"
|
||||
,"korean_1k"
|
||||
,"korean_5k"
|
||||
,"khmer"
|
||||
,"chinese_simplified"
|
||||
,"chinese_simplified_1k"
|
||||
,"chinese_simplified_5k"
|
||||
,"chinese_simplified_10k"
|
||||
,"chinese_simplified_50k"
|
||||
,"chinese_traditional"
|
||||
,"russian"
|
||||
,"russian_1k"
|
||||
,"russian_5k"
|
||||
,"russian_10k"
|
||||
,"russian_25k"
|
||||
,"russian_50k"
|
||||
,"russian_375k"
|
||||
,"russian_contractions"
|
||||
,"russian_contractions_1k"
|
||||
,"russian_abbreviations"
|
||||
,"ukrainian"
|
||||
,"ukrainian_1k"
|
||||
,"ukrainian_10k"
|
||||
,"ukrainian_50k"
|
||||
,"ukrainian_endings"
|
||||
,"ukrainian_latynka"
|
||||
,"ukrainian_latynka_1k"
|
||||
,"ukrainian_latynka_10k"
|
||||
,"ukrainian_latynka_50k"
|
||||
,"ukrainian_latynka_endings"
|
||||
,"portuguese"
|
||||
,"portuguese_acentos_e_cedilha"
|
||||
,"portuguese_1k"
|
||||
,"portuguese_3k"
|
||||
,"portuguese_5k"
|
||||
,"portuguese_320k"
|
||||
,"portuguese_550k"
|
||||
,"indonesian"
|
||||
,"indonesian_1k"
|
||||
,"indonesian_10k"
|
||||
,"kurdish_central"
|
||||
,"kurdish_central_2k"
|
||||
,"kurdish_central_4k"
|
||||
,"german"
|
||||
,"german_1k"
|
||||
,"german_10k"
|
||||
,"german_250k"
|
||||
,"swiss_german"
|
||||
,"swiss_german_1k"
|
||||
,"swiss_german_2k"
|
||||
,"afrikaans"
|
||||
,"afrikaans_1k"
|
||||
,"afrikaans_10k"
|
||||
,"georgian"
|
||||
,"tamil"
|
||||
,"tamil_1k"
|
||||
,"tanglish"
|
||||
,"tamil_old"
|
||||
,"telugu"
|
||||
,"telugu_1k"
|
||||
,"greek"
|
||||
,"greek_1k"
|
||||
,"greek_5k"
|
||||
,"greek_10k"
|
||||
,"greek_25k"
|
||||
,"greeklish"
|
||||
,"greeklish_1k"
|
||||
,"greeklish_5k"
|
||||
,"greeklish_10k"
|
||||
,"greeklish_25k"
|
||||
,"turkish"
|
||||
,"turkish_1k"
|
||||
,"turkish_5k"
|
||||
,"irish"
|
||||
,"italian"
|
||||
,"italian_1k"
|
||||
,"italian_7k"
|
||||
,"italian_60k"
|
||||
,"italian_280k"
|
||||
,"friulian"
|
||||
,"latin"
|
||||
,"galician"
|
||||
,"thai"
|
||||
,"thai_20k"
|
||||
,"polish"
|
||||
,"polish_2k"
|
||||
,"polish_5k"
|
||||
,"polish_10k"
|
||||
,"polish_20k"
|
||||
,"polish_40k"
|
||||
,"polish_200k"
|
||||
,"czech"
|
||||
,"czech_1k"
|
||||
,"czech_10k"
|
||||
,"slovak"
|
||||
,"slovak_1k"
|
||||
,"slovak_10k"
|
||||
,"slovenian"
|
||||
,"slovenian_1k"
|
||||
,"slovenian_5k"
|
||||
,"croatian"
|
||||
,"croatian_1k"
|
||||
,"dutch"
|
||||
,"dutch_1k"
|
||||
,"dutch_10k"
|
||||
,"filipino"
|
||||
,"filipino_1k"
|
||||
,"danish"
|
||||
,"danish_1k"
|
||||
,"danish_10k"
|
||||
,"hungarian"
|
||||
,"hungarian_2k"
|
||||
,"norwegian_bokmal"
|
||||
,"norwegian_bokmal_1k"
|
||||
,"norwegian_bokmal_5k"
|
||||
,"norwegian_bokmal_10k"
|
||||
,"norwegian_bokmal_150k"
|
||||
,"norwegian_bokmal_600k"
|
||||
,"norwegian_nynorsk"
|
||||
,"norwegian_nynorsk_1k"
|
||||
,"norwegian_nynorsk_5k"
|
||||
,"norwegian_nynorsk_10k"
|
||||
,"norwegian_nynorsk_100k"
|
||||
,"norwegian_nynorsk_400k"
|
||||
,"hebrew"
|
||||
,"hebrew_1k"
|
||||
,"hebrew_5k"
|
||||
,"hebrew_10k"
|
||||
,"icelandic_1k"
|
||||
,"romanian"
|
||||
,"romanian_1k"
|
||||
,"romanian_5k"
|
||||
,"romanian_10k"
|
||||
,"romanian_25k"
|
||||
,"romanian_50k"
|
||||
,"romanian_100k"
|
||||
,"romanian_200k"
|
||||
,"lorem_ipsum"
|
||||
,"finnish"
|
||||
,"finnish_1k"
|
||||
,"finnish_10k"
|
||||
,"estonian"
|
||||
,"estonian_1k"
|
||||
,"estonian_5k"
|
||||
,"estonian_10k"
|
||||
,"udmurt"
|
||||
,"welsh"
|
||||
,"welsh_1k"
|
||||
,"persian"
|
||||
,"persian_1k"
|
||||
,"persian_5k"
|
||||
,"persian_20k"
|
||||
,"persian_romanized"
|
||||
,"marathi"
|
||||
,"kazakh"
|
||||
,"kazakh_1k"
|
||||
,"vietnamese"
|
||||
,"vietnamese_1k"
|
||||
,"vietnamese_5k"
|
||||
,"jyutping"
|
||||
,"pinyin"
|
||||
,"pinyin_1k"
|
||||
,"pinyin_10k"
|
||||
,"hausa"
|
||||
,"hausa_1k"
|
||||
,"swedish"
|
||||
,"swedish_1k"
|
||||
,"swedish_diacritics"
|
||||
,"serbian_latin"
|
||||
,"serbian_latin_10k"
|
||||
,"serbian"
|
||||
,"serbian_10k"
|
||||
,"yoruba_1k"
|
||||
,"swahili_1k"
|
||||
,"maori_1k"
|
||||
,"catalan"
|
||||
,"catalan_1k"
|
||||
,"lojban_gismu"
|
||||
,"lojban_cmavo"
|
||||
,"lithuanian"
|
||||
,"lithuanian_1k"
|
||||
,"lithuanian_3k"
|
||||
,"bulgarian"
|
||||
,"bulgarian_latin"
|
||||
,"bangla"
|
||||
,"bangla_letters"
|
||||
,"bangla_10k"
|
||||
,"bosnian"
|
||||
,"bosnian_4k"
|
||||
,"toki_pona"
|
||||
,"toki_pona_ku_suli"
|
||||
,"toki_pona_ku_lili"
|
||||
,"esperanto"
|
||||
,"esperanto_1k"
|
||||
,"esperanto_10k"
|
||||
,"esperanto_25k"
|
||||
,"esperanto_36k"
|
||||
,"esperanto_x_sistemo"
|
||||
,"esperanto_x_sistemo_1k"
|
||||
,"esperanto_x_sistemo_10k"
|
||||
,"esperanto_x_sistemo_25k"
|
||||
,"esperanto_x_sistemo_36k"
|
||||
,"esperanto_h_sistemo"
|
||||
,"esperanto_h_sistemo_1k"
|
||||
,"esperanto_h_sistemo_10k"
|
||||
,"esperanto_h_sistemo_25k"
|
||||
,"esperanto_h_sistemo_36k"
|
||||
,"kyrgyz"
|
||||
,"kyrgyz_1k"
|
||||
,"urdu"
|
||||
,"urdu_1k"
|
||||
,"urdu_5k"
|
||||
,"urdish"
|
||||
,"albanian"
|
||||
,"albanian_1k"
|
||||
,"shona"
|
||||
,"shona_1k"
|
||||
,"armenian"
|
||||
,"armenian_1k"
|
||||
,"armenian_western"
|
||||
,"armenian_western_1k"
|
||||
,"myanmar_burmese"
|
||||
,"japanese_hiragana"
|
||||
,"japanese_katakana"
|
||||
,"japanese_romaji"
|
||||
,"japanese_romaji_1k"
|
||||
,"sinhala"
|
||||
,"latvian"
|
||||
,"latvian_1k"
|
||||
,"maltese"
|
||||
,"maltese_1k"
|
||||
,"twitch_emotes"
|
||||
,"git"
|
||||
,"pig_latin"
|
||||
,"hindi"
|
||||
,"hindi_1k"
|
||||
,"hinglish"
|
||||
,"gujarati"
|
||||
,"gujarati_1k"
|
||||
,"macedonian"
|
||||
,"macedonian_1k"
|
||||
,"macedonian_10k"
|
||||
,"macedonian_75k"
|
||||
,"belarusian"
|
||||
,"belarusian_1k"
|
||||
,"belarusian_5k"
|
||||
,"belarusian_10k"
|
||||
,"belarusian_25k"
|
||||
,"belarusian_50k"
|
||||
,"belarusian_100k"
|
||||
,"belarusian_lacinka"
|
||||
,"belarusian_lacinka_1k"
|
||||
,"tatar"
|
||||
,"tatar_1k"
|
||||
,"tatar_5k"
|
||||
,"tatar_9k"
|
||||
,"tatar_crimean"
|
||||
,"tatar_crimean_1k"
|
||||
,"tatar_crimean_5k"
|
||||
,"tatar_crimean_10k"
|
||||
,"tatar_crimean_15k"
|
||||
,"tatar_crimean_cyrillic"
|
||||
,"tatar_crimean_cyrillic_1k"
|
||||
,"tatar_crimean_cyrillic_5k"
|
||||
,"tatar_crimean_cyrillic_10k"
|
||||
,"tatar_crimean_cyrillic_15k"
|
||||
,"uzbek"
|
||||
,"uzbek_1k"
|
||||
,"uzbek_70k"
|
||||
,"malayalam"
|
||||
,"amharic"
|
||||
,"amharic_1k"
|
||||
,"amharic_5k"
|
||||
,"oromo"
|
||||
,"oromo_1k"
|
||||
,"oromo_5k"
|
||||
,"wordle"
|
||||
,"league_of_legends"
|
||||
,"wordle_1k"
|
||||
,"typing_of_the_dead"
|
||||
,"yiddish"
|
||||
,"frisian"
|
||||
,"frisian_1k"
|
||||
,"pashto"
|
||||
,"euskera"
|
||||
,"klingon"
|
||||
,"klingon_1k"
|
||||
,"quenya"
|
||||
,"occitan"
|
||||
,"occitan_1k"
|
||||
,"occitan_2k"
|
||||
,"occitan_5k"
|
||||
,"occitan_10k"
|
||||
,"bashkir"
|
||||
,"zulu"
|
||||
,"code_python"
|
||||
,"code_python_1k"
|
||||
,"code_python_2k"
|
||||
,"code_python_5k"
|
||||
,"code_fsharp"
|
||||
,"code_c"
|
||||
,"code_csharp"
|
||||
,"code_css"
|
||||
,"code_c++"
|
||||
,"code_dart"
|
||||
,"code_brainfck"
|
||||
,"code_javascript"
|
||||
,"code_javascript_1k"
|
||||
,"code_javascript_react"
|
||||
,"code_jule"
|
||||
,"code_julia"
|
||||
,"code_haskell"
|
||||
,"code_html"
|
||||
,"code_nim"
|
||||
,"code_nix"
|
||||
,"code_pascal"
|
||||
,"code_java"
|
||||
,"code_kotlin"
|
||||
,"code_go"
|
||||
,"code_rockstar"
|
||||
,"code_rust"
|
||||
,"code_ruby"
|
||||
,"code_r"
|
||||
,"code_r_2k"
|
||||
,"code_swift"
|
||||
,"code_scala"
|
||||
,"code_bash"
|
||||
,"code_powershell"
|
||||
,"code_lua"
|
||||
,"code_luau"
|
||||
,"code_latex"
|
||||
,"code_typst"
|
||||
,"code_matlab"
|
||||
,"code_sql"
|
||||
,"code_perl"
|
||||
,"code_php"
|
||||
,"code_vim"
|
||||
,"code_vimscript"
|
||||
,"code_opencl"
|
||||
,"code_visual_basic"
|
||||
,"code_arduino"
|
||||
,"code_systemverilog"
|
||||
,"code_elixir"
|
||||
,"code_zig"
|
||||
,"code_gdscript"
|
||||
,"code_gdscript_2"
|
||||
,"code_assembly"
|
||||
,"code_v"
|
||||
,"code_ook"
|
||||
,"code_typescript"
|
||||
,"code_odin"
|
||||
,"xhosa"
|
||||
,"xhosa_3k"
|
||||
,"tibetan"
|
||||
,"tibetan_1k"
|
||||
,"code_cobol"
|
||||
,"code_common_lisp"
|
||||
,"docker_file"
|
||||
,"code_fortran"
|
||||
]
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
// chinese: {leftToRight: true, words: ["一","人","里","会","没","她","吗","去","也","有","这","那","不","什","个","来","要","就","我","你","的","是","了","他","么","们","在","说","为","好","吧","知道","我的","和","你的","想","只","很","都","对","把","啊","怎","得","还","过","不是","到","样","飞","远","身","任何","生活","够","号","兰","瑞","达","或","愿","蒂","別","军","正","是不是","证","不用","三","乐","吉","男人","告訴","路","搞","可是","与","次","狗","决","金","史","姆","部","正在","活","刚","回家","贝","如何","须","战","不會","夫","喂","父","亚","肯定","女孩","世界","不要","些","不知道","不能","因","觉","发","像","太","但是","多","打","机","來","好了","用","他的","诉","德","叫","什麼","真","干","心","走","比","死","嘿","出","车","一下","中","好吧","需要","经","妈","候","长","而","错","好的","间","又","国","起","动","杀","于","种","去了","担","名","混蛋","礼","幹","不了","有些","過","後","击","漂亮","神","多少","海","每","哥","教","走吧","好像","单","公","林","女","忙","火","钟","家伙","科","回去","最后","水","不管","麦","泻","鬼","還","船","永","安全","那個","爾","這麼","满","风","皮","威","据","鲁","转","相"]},
|
||||
// chinese_simplified: {leftToRight: true, words: ["我","的","你","是","了","不","们","这","一","他","么","在","有","个","好","来","人","那","要","会","就","什","没","到","说","吗","为","想","能","上","去","道","她","很","看","可","知","得","过","吧","还","对","里","以","都","事","子","生","时","样","也","和","下","真","现","做","大","啊","怎","出","点","起","天","把","开","让","给","但","谢","着","只","些","如","家","后","儿","多","意","别","所","话","小","自","回","然","果","发","见","心","走","定","听","觉","太","该","当","经","妈","用","打","地","再","因","呢","女","告","最","手","前","找","行","快","而","死","先","像","等","被","从","明","中","哦","情","作","跟","面","诉","爱","已","之","问","错","孩","斯","成","它","感","干","法","电","间","哪","西","己","候","次","信","欢","正","实","关","进","车","年","喜","认","克","爸","谁","方","老","应","比","帮","无","晚","动","头","机","分","特","相","全","杀","需","放","常","直","才","美","于","带","今","力","工","许","东","名","同","长","亲","种","者","嘿","白","学","安","尔","叫","理"]},
|
||||
// korean: {leftToRight: true, words: ["로","나는","그의","그","그","했다","에 대한","에","아르","와","그들","있다","에","일","이","이","부터","에 의해","뜨거운","단어","하지만","무엇","다소","이다","그","당신","또는","했다","에","의","에","과","이","에","우리","수","아웃","다른","했다","하는","할","자신의","시간","면","것","방법","말했다","이","각","이야기","하지","세트","세","필요","공기","잘","또한","재생","작은","끝","넣어","홈","읽기","손","포트","큰","철자","추가","도","땅","여기","해야","큰","높은","이러한","따라","행위","이유","문의","남자","변경","갔다","빛","종류","오프","필요가있다","집","사진","시험","우리","다시","동물","포인트","어머니","세계","가까운","구축","자기","지구","아버지","모든","새로운","일","일부","소요","도착","장소","만든","살고있다","어디에","후","다시","작은","만","둥근","사람","년","온","쇼","모든","좋은","나를","제공","우리의","아래의","이름","대단히","를 통해","단지","양식","문장","큰","생각","말","도움","낮은","온라인","차이","회전","원인","많은","의미","이전","움직임","바로","소년","늙은","너무","동일","그녀","모든","그곳에","때","올라","사용","당신의","방법","에 대한","많은","다음","그","쓰기","것","같은","그래서","이들","그녀의","긴","확인","일","참조","그","두","이","봐","더","일","수","이동","올","한","수","소리","없음","가장","사람들","내","이상","알고","물","보다","통화","첫째","사람","수도","아래로","측면","하고","지금","발견"]},
|
||||
|
|
@ -55,7 +55,7 @@
|
|||
"pretty-fix-pkg": "prettier --write ./packages",
|
||||
"pr-check-lint-json": "cd frontend && eslint './static/**/*.json'",
|
||||
"pr-check-quote-json": "cd frontend && npx gulp pr-check-quote-json",
|
||||
"pr-check-language-json": "cd frontend && npx gulp pr-check-language-json",
|
||||
"pr-check-language-json": "cd frontend && npx gulp pr-check-language-json && turbo test -- constants/languages",
|
||||
"pr-check-other-json": "cd frontend && npx gulp pr-check-other-json && turbo test -- constants/layouts constants/themes"
|
||||
},
|
||||
"engines": {
|
||||
|
|
|
|||
|
|
@ -9,9 +9,9 @@ import {
|
|||
LeaderboardEntrySchema,
|
||||
XpLeaderboardEntrySchema,
|
||||
} from "./schemas/leaderboards";
|
||||
import { LanguageSchema } from "./schemas/util";
|
||||
import { Mode2Schema, ModeSchema } from "./schemas/shared";
|
||||
import { initContract } from "@ts-rest/core";
|
||||
import { LanguageSchema } from "./schemas/languages";
|
||||
|
||||
const LanguageAndModeQuerySchema = z.object({
|
||||
language: LanguageSchema,
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { z } from "zod";
|
|||
import { CommonResponses, meta, responseWithData } from "./schemas/api";
|
||||
import { SpeedHistogramSchema, TypingStatsSchema } from "./schemas/public";
|
||||
import { Mode2Schema, ModeSchema } from "./schemas/shared";
|
||||
import { LanguageSchema } from "./schemas/util";
|
||||
import { LanguageSchema } from "./schemas/languages";
|
||||
|
||||
export const GetSpeedHistogramQuerySchema = z
|
||||
.object({
|
||||
|
|
|
|||
|
|
@ -15,7 +15,8 @@ import {
|
|||
QuoteReportReasonSchema,
|
||||
QuoteSchema,
|
||||
} from "./schemas/quotes";
|
||||
import { IdSchema, LanguageSchema, NullableStringSchema } from "./schemas/util";
|
||||
import { IdSchema, NullableStringSchema } from "./schemas/util";
|
||||
import { LanguageSchema } from "./schemas/languages";
|
||||
|
||||
export const GetQuotesResponseSchema = responseWithData(z.array(QuoteSchema));
|
||||
export type GetQuotesResponse = z.infer<typeof GetQuotesResponseSchema>;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import { z, ZodSchema } from "zod";
|
||||
import { LanguageSchema } from "./util";
|
||||
import * as Shared from "./shared";
|
||||
import * as Themes from "./themes";
|
||||
import * as Layouts from "./layouts";
|
||||
import { LanguageSchema } from "./languages";
|
||||
|
||||
export const SmoothCaretSchema = z.enum(["off", "slow", "medium", "fast"]);
|
||||
export type SmoothCaret = z.infer<typeof SmoothCaretSchema>;
|
||||
|
|
|
|||
417
packages/contracts/src/schemas/languages.ts
Normal file
417
packages/contracts/src/schemas/languages.ts
Normal file
|
|
@ -0,0 +1,417 @@
|
|||
import { z } from "zod";
|
||||
import { customEnumErrorHandler } from "./util";
|
||||
|
||||
export const LanguageSchema = z.enum(
|
||||
[
|
||||
"english",
|
||||
"english_1k",
|
||||
"english_5k",
|
||||
"english_10k",
|
||||
"english_25k",
|
||||
"english_450k",
|
||||
"english_commonly_misspelled",
|
||||
"english_contractions",
|
||||
"english_doubleletter",
|
||||
"english_shakespearean",
|
||||
"english_old",
|
||||
"english_medical",
|
||||
"spanish",
|
||||
"spanish_1k",
|
||||
"spanish_10k",
|
||||
"spanish_650k",
|
||||
"french",
|
||||
"french_1k",
|
||||
"french_2k",
|
||||
"french_10k",
|
||||
"french_600k",
|
||||
"french_bitoduc",
|
||||
"nepali",
|
||||
"nepali_1k",
|
||||
"nepali_romanized",
|
||||
"sanskrit",
|
||||
"sanskrit_roman",
|
||||
"santali",
|
||||
"azerbaijani",
|
||||
"azerbaijani_1k",
|
||||
"arabic",
|
||||
"arabic_10k",
|
||||
"arabic_egypt",
|
||||
"arabic_egypt_1k",
|
||||
"malagasy",
|
||||
"malagasy_1k",
|
||||
"malay",
|
||||
"malay_1k",
|
||||
"mongolian",
|
||||
"mongolian_10k",
|
||||
"kannada",
|
||||
"korean",
|
||||
"korean_1k",
|
||||
"korean_5k",
|
||||
"khmer",
|
||||
"chinese_simplified",
|
||||
"chinese_simplified_1k",
|
||||
"chinese_simplified_5k",
|
||||
"chinese_simplified_10k",
|
||||
"chinese_simplified_50k",
|
||||
"chinese_traditional",
|
||||
"russian",
|
||||
"russian_1k",
|
||||
"russian_5k",
|
||||
"russian_10k",
|
||||
"russian_25k",
|
||||
"russian_50k",
|
||||
"russian_375k",
|
||||
"russian_contractions",
|
||||
"russian_contractions_1k",
|
||||
"russian_abbreviations",
|
||||
"ukrainian",
|
||||
"ukrainian_1k",
|
||||
"ukrainian_10k",
|
||||
"ukrainian_50k",
|
||||
"ukrainian_endings",
|
||||
"ukrainian_latynka",
|
||||
"ukrainian_latynka_1k",
|
||||
"ukrainian_latynka_10k",
|
||||
"ukrainian_latynka_50k",
|
||||
"ukrainian_latynka_endings",
|
||||
"portuguese",
|
||||
"portuguese_acentos_e_cedilha",
|
||||
"portuguese_1k",
|
||||
"portuguese_3k",
|
||||
"portuguese_5k",
|
||||
"portuguese_320k",
|
||||
"portuguese_550k",
|
||||
"indonesian",
|
||||
"indonesian_1k",
|
||||
"indonesian_10k",
|
||||
"kurdish_central",
|
||||
"kurdish_central_2k",
|
||||
"kurdish_central_4k",
|
||||
"german",
|
||||
"german_1k",
|
||||
"german_10k",
|
||||
"german_250k",
|
||||
"swiss_german",
|
||||
"swiss_german_1k",
|
||||
"swiss_german_2k",
|
||||
"afrikaans",
|
||||
"afrikaans_1k",
|
||||
"afrikaans_10k",
|
||||
"georgian",
|
||||
"tamil",
|
||||
"tamil_1k",
|
||||
"tanglish",
|
||||
"tamil_old",
|
||||
"telugu",
|
||||
"telugu_1k",
|
||||
"greek",
|
||||
"greek_1k",
|
||||
"greek_5k",
|
||||
"greek_10k",
|
||||
"greek_25k",
|
||||
"greeklish",
|
||||
"greeklish_1k",
|
||||
"greeklish_5k",
|
||||
"greeklish_10k",
|
||||
"greeklish_25k",
|
||||
"turkish",
|
||||
"turkish_1k",
|
||||
"turkish_5k",
|
||||
"irish",
|
||||
"italian",
|
||||
"italian_1k",
|
||||
"italian_7k",
|
||||
"italian_60k",
|
||||
"italian_280k",
|
||||
"friulian",
|
||||
"latin",
|
||||
"galician",
|
||||
"thai",
|
||||
"thai_20k",
|
||||
"polish",
|
||||
"polish_2k",
|
||||
"polish_5k",
|
||||
"polish_10k",
|
||||
"polish_20k",
|
||||
"polish_40k",
|
||||
"polish_200k",
|
||||
"czech",
|
||||
"czech_1k",
|
||||
"czech_10k",
|
||||
"slovak",
|
||||
"slovak_1k",
|
||||
"slovak_10k",
|
||||
"slovenian",
|
||||
"slovenian_1k",
|
||||
"slovenian_5k",
|
||||
"croatian",
|
||||
"croatian_1k",
|
||||
"dutch",
|
||||
"dutch_1k",
|
||||
"dutch_10k",
|
||||
"filipino",
|
||||
"filipino_1k",
|
||||
"danish",
|
||||
"danish_1k",
|
||||
"danish_10k",
|
||||
"hungarian",
|
||||
"hungarian_2k",
|
||||
"norwegian_bokmal",
|
||||
"norwegian_bokmal_1k",
|
||||
"norwegian_bokmal_5k",
|
||||
"norwegian_bokmal_10k",
|
||||
"norwegian_bokmal_150k",
|
||||
"norwegian_bokmal_600k",
|
||||
"norwegian_nynorsk",
|
||||
"norwegian_nynorsk_1k",
|
||||
"norwegian_nynorsk_5k",
|
||||
"norwegian_nynorsk_10k",
|
||||
"norwegian_nynorsk_100k",
|
||||
"norwegian_nynorsk_400k",
|
||||
"hebrew",
|
||||
"hebrew_1k",
|
||||
"hebrew_5k",
|
||||
"hebrew_10k",
|
||||
"icelandic_1k",
|
||||
"romanian",
|
||||
"romanian_1k",
|
||||
"romanian_5k",
|
||||
"romanian_10k",
|
||||
"romanian_25k",
|
||||
"romanian_50k",
|
||||
"romanian_100k",
|
||||
"romanian_200k",
|
||||
"lorem_ipsum",
|
||||
"finnish",
|
||||
"finnish_1k",
|
||||
"finnish_10k",
|
||||
"estonian",
|
||||
"estonian_1k",
|
||||
"estonian_5k",
|
||||
"estonian_10k",
|
||||
"udmurt",
|
||||
"welsh",
|
||||
"welsh_1k",
|
||||
"persian",
|
||||
"persian_1k",
|
||||
"persian_5k",
|
||||
"persian_20k",
|
||||
"persian_romanized",
|
||||
"marathi",
|
||||
"kazakh",
|
||||
"kazakh_1k",
|
||||
"vietnamese",
|
||||
"vietnamese_1k",
|
||||
"vietnamese_5k",
|
||||
"jyutping",
|
||||
"pinyin",
|
||||
"pinyin_1k",
|
||||
"pinyin_10k",
|
||||
"hausa",
|
||||
"hausa_1k",
|
||||
"swedish",
|
||||
"swedish_1k",
|
||||
"swedish_diacritics",
|
||||
"serbian_latin",
|
||||
"serbian_latin_10k",
|
||||
"serbian",
|
||||
"serbian_10k",
|
||||
"yoruba_1k",
|
||||
"swahili_1k",
|
||||
"maori_1k",
|
||||
"catalan",
|
||||
"catalan_1k",
|
||||
"lojban_gismu",
|
||||
"lojban_cmavo",
|
||||
"lithuanian",
|
||||
"lithuanian_1k",
|
||||
"lithuanian_3k",
|
||||
"bulgarian",
|
||||
"bulgarian_latin",
|
||||
"bangla",
|
||||
"bangla_letters",
|
||||
"bangla_10k",
|
||||
"bosnian",
|
||||
"bosnian_4k",
|
||||
"toki_pona",
|
||||
"toki_pona_ku_suli",
|
||||
"toki_pona_ku_lili",
|
||||
"esperanto",
|
||||
"esperanto_1k",
|
||||
"esperanto_10k",
|
||||
"esperanto_25k",
|
||||
"esperanto_36k",
|
||||
"esperanto_x_sistemo",
|
||||
"esperanto_x_sistemo_1k",
|
||||
"esperanto_x_sistemo_10k",
|
||||
"esperanto_x_sistemo_25k",
|
||||
"esperanto_x_sistemo_36k",
|
||||
"esperanto_h_sistemo",
|
||||
"esperanto_h_sistemo_1k",
|
||||
"esperanto_h_sistemo_10k",
|
||||
"esperanto_h_sistemo_25k",
|
||||
"esperanto_h_sistemo_36k",
|
||||
"kyrgyz",
|
||||
"kyrgyz_1k",
|
||||
"urdu",
|
||||
"urdu_1k",
|
||||
"urdu_5k",
|
||||
"urdish",
|
||||
"albanian",
|
||||
"albanian_1k",
|
||||
"shona",
|
||||
"shona_1k",
|
||||
"armenian",
|
||||
"armenian_1k",
|
||||
"armenian_western",
|
||||
"armenian_western_1k",
|
||||
"myanmar_burmese",
|
||||
"japanese_hiragana",
|
||||
"japanese_katakana",
|
||||
"japanese_romaji",
|
||||
"japanese_romaji_1k",
|
||||
"sinhala",
|
||||
"latvian",
|
||||
"latvian_1k",
|
||||
"maltese",
|
||||
"maltese_1k",
|
||||
"twitch_emotes",
|
||||
"git",
|
||||
"pig_latin",
|
||||
"hindi",
|
||||
"hindi_1k",
|
||||
"hinglish",
|
||||
"gujarati",
|
||||
"gujarati_1k",
|
||||
"macedonian",
|
||||
"macedonian_1k",
|
||||
"macedonian_10k",
|
||||
"macedonian_75k",
|
||||
"belarusian",
|
||||
"belarusian_1k",
|
||||
"belarusian_5k",
|
||||
"belarusian_10k",
|
||||
"belarusian_25k",
|
||||
"belarusian_50k",
|
||||
"belarusian_100k",
|
||||
"belarusian_lacinka",
|
||||
"belarusian_lacinka_1k",
|
||||
"tatar",
|
||||
"tatar_1k",
|
||||
"tatar_5k",
|
||||
"tatar_9k",
|
||||
"tatar_crimean",
|
||||
"tatar_crimean_1k",
|
||||
"tatar_crimean_5k",
|
||||
"tatar_crimean_10k",
|
||||
"tatar_crimean_15k",
|
||||
"tatar_crimean_cyrillic",
|
||||
"tatar_crimean_cyrillic_1k",
|
||||
"tatar_crimean_cyrillic_5k",
|
||||
"tatar_crimean_cyrillic_10k",
|
||||
"tatar_crimean_cyrillic_15k",
|
||||
"uzbek",
|
||||
"uzbek_1k",
|
||||
"uzbek_70k",
|
||||
"malayalam",
|
||||
"amharic",
|
||||
"amharic_1k",
|
||||
"amharic_5k",
|
||||
"oromo",
|
||||
"oromo_1k",
|
||||
"oromo_5k",
|
||||
"wordle",
|
||||
"league_of_legends",
|
||||
"wordle_1k",
|
||||
"typing_of_the_dead",
|
||||
"yiddish",
|
||||
"frisian",
|
||||
"frisian_1k",
|
||||
"pashto",
|
||||
"euskera",
|
||||
"klingon",
|
||||
"klingon_1k",
|
||||
"quenya",
|
||||
"occitan",
|
||||
"occitan_1k",
|
||||
"occitan_2k",
|
||||
"occitan_5k",
|
||||
"occitan_10k",
|
||||
"bashkir",
|
||||
"zulu",
|
||||
"kabyle",
|
||||
"kabyle_1k",
|
||||
"kabyle_2k",
|
||||
"kabyle_5k",
|
||||
"kabyle_10k",
|
||||
"code_python",
|
||||
"code_python_1k",
|
||||
"code_python_2k",
|
||||
"code_python_5k",
|
||||
"code_fsharp",
|
||||
"code_c",
|
||||
"code_csharp",
|
||||
"code_css",
|
||||
"code_c++",
|
||||
"code_dart",
|
||||
"code_brainfck",
|
||||
"code_javascript",
|
||||
"code_javascript_1k",
|
||||
"code_javascript_react",
|
||||
"code_jule",
|
||||
"code_julia",
|
||||
"code_haskell",
|
||||
"code_html",
|
||||
"code_nim",
|
||||
"code_nix",
|
||||
"code_pascal",
|
||||
"code_java",
|
||||
"code_kotlin",
|
||||
"code_go",
|
||||
"code_rockstar",
|
||||
"code_rust",
|
||||
"code_ruby",
|
||||
"code_r",
|
||||
"code_r_2k",
|
||||
"code_swift",
|
||||
"code_scala",
|
||||
"code_bash",
|
||||
"code_powershell",
|
||||
"code_lua",
|
||||
"code_luau",
|
||||
"code_latex",
|
||||
"code_typst",
|
||||
"code_matlab",
|
||||
"code_sql",
|
||||
"code_perl",
|
||||
"code_php",
|
||||
"code_vim",
|
||||
"code_vimscript",
|
||||
"code_opencl",
|
||||
"code_visual_basic",
|
||||
"code_arduino",
|
||||
"code_systemverilog",
|
||||
"code_elixir",
|
||||
"code_zig",
|
||||
"code_gdscript",
|
||||
"code_gdscript_2",
|
||||
"code_assembly",
|
||||
"code_v",
|
||||
"code_ook",
|
||||
"code_typescript",
|
||||
"code_odin",
|
||||
"xhosa",
|
||||
"xhosa_3k",
|
||||
"tibetan",
|
||||
"tibetan_1k",
|
||||
"code_cobol",
|
||||
"code_common_lisp",
|
||||
"docker_file",
|
||||
"code_fortran",
|
||||
],
|
||||
{
|
||||
errorMap: customEnumErrorHandler("Must be a supported language"),
|
||||
}
|
||||
);
|
||||
|
||||
export type Language = z.infer<typeof LanguageSchema>;
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
import { z } from "zod";
|
||||
import { IdSchema, LanguageSchema } from "./util";
|
||||
import { IdSchema } from "./util";
|
||||
import { LanguageSchema } from "./languages";
|
||||
|
||||
export const QuoteIdSchema = z
|
||||
.number()
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ import {
|
|||
PercentageSchema,
|
||||
token,
|
||||
WpmSchema,
|
||||
LanguageSchema,
|
||||
} from "./util";
|
||||
import { LanguageSchema } from "./languages";
|
||||
import { Mode, Mode2, Mode2Schema, ModeSchema } from "./shared";
|
||||
import { DifficultySchema, FunboxSchema } from "./configs";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { literal, z } from "zod";
|
||||
import { StringNumberSchema } from "./util";
|
||||
import { LanguageSchema } from "./languages";
|
||||
|
||||
//used by config and shared
|
||||
export const DifficultySchema = z.enum(["normal", "expert", "master"]);
|
||||
|
|
@ -11,10 +12,7 @@ export const PersonalBestSchema = z.object({
|
|||
consistency: z.number().nonnegative().max(100),
|
||||
difficulty: DifficultySchema,
|
||||
lazyMode: z.boolean().optional(),
|
||||
language: z
|
||||
.string()
|
||||
.max(100)
|
||||
.regex(/[\w+]+/),
|
||||
language: LanguageSchema,
|
||||
punctuation: z.boolean().optional(),
|
||||
numbers: z.boolean().optional(),
|
||||
raw: z.number().nonnegative(),
|
||||
|
|
|
|||
|
|
@ -1,188 +1,194 @@
|
|||
import { z } from "zod";
|
||||
import { customEnumErrorHandler } from "./util";
|
||||
|
||||
export const ThemeNameSchema = z.enum([
|
||||
"8008",
|
||||
"80s_after_dark",
|
||||
"9009",
|
||||
"aether",
|
||||
"alduin",
|
||||
"alpine",
|
||||
"anti_hero",
|
||||
"arch",
|
||||
"aurora",
|
||||
"beach",
|
||||
"bento",
|
||||
"bingsu",
|
||||
"bliss",
|
||||
"blue_dolphin",
|
||||
"blueberry_dark",
|
||||
"blueberry_light",
|
||||
"botanical",
|
||||
"bouquet",
|
||||
"breeze",
|
||||
"bushido",
|
||||
"cafe",
|
||||
"camping",
|
||||
"carbon",
|
||||
"catppuccin",
|
||||
"chaos_theory",
|
||||
"cheesecake",
|
||||
"cherry_blossom",
|
||||
"comfy",
|
||||
"copper",
|
||||
"creamsicle",
|
||||
"cy_red",
|
||||
"cyberspace",
|
||||
"dark",
|
||||
"dark_magic_girl",
|
||||
"dark_note",
|
||||
"darling",
|
||||
"deku",
|
||||
"desert_oasis",
|
||||
"dev",
|
||||
"diner",
|
||||
"dino",
|
||||
"discord",
|
||||
"dmg",
|
||||
"dollar",
|
||||
"dots",
|
||||
"dracula",
|
||||
"drowning",
|
||||
"dualshot",
|
||||
"earthsong",
|
||||
"everblush",
|
||||
"evil_eye",
|
||||
"ez_mode",
|
||||
"fire",
|
||||
"fledgling",
|
||||
"fleuriste",
|
||||
"floret",
|
||||
"froyo",
|
||||
"frozen_llama",
|
||||
"fruit_chew",
|
||||
"fundamentals",
|
||||
"future_funk",
|
||||
"github",
|
||||
"godspeed",
|
||||
"graen",
|
||||
"grand_prix",
|
||||
"grape",
|
||||
"gruvbox_dark",
|
||||
"gruvbox_light",
|
||||
"hammerhead",
|
||||
"hanok",
|
||||
"hedge",
|
||||
"honey",
|
||||
"horizon",
|
||||
"husqy",
|
||||
"iceberg_dark",
|
||||
"iceberg_light",
|
||||
"incognito",
|
||||
"ishtar",
|
||||
"iv_clover",
|
||||
"iv_spade",
|
||||
"joker",
|
||||
"laser",
|
||||
"lavender",
|
||||
"leather",
|
||||
"lil_dragon",
|
||||
"lilac_mist",
|
||||
"lime",
|
||||
"luna",
|
||||
"macroblank",
|
||||
"magic_girl",
|
||||
"mashu",
|
||||
"matcha_moccha",
|
||||
"material",
|
||||
"matrix",
|
||||
"menthol",
|
||||
"metaverse",
|
||||
"metropolis",
|
||||
"mexican",
|
||||
"miami",
|
||||
"miami_nights",
|
||||
"midnight",
|
||||
"milkshake",
|
||||
"mint",
|
||||
"mizu",
|
||||
"modern_dolch",
|
||||
"modern_dolch_light",
|
||||
"modern_ink",
|
||||
"monokai",
|
||||
"moonlight",
|
||||
"mountain",
|
||||
"mr_sleeves",
|
||||
"ms_cupcakes",
|
||||
"muted",
|
||||
"nautilus",
|
||||
"nebula",
|
||||
"night_runner",
|
||||
"nord",
|
||||
"nord_light",
|
||||
"norse",
|
||||
"oblivion",
|
||||
"olive",
|
||||
"olivia",
|
||||
"onedark",
|
||||
"our_theme",
|
||||
"paper",
|
||||
"passion_fruit",
|
||||
"pastel",
|
||||
"peach_blossom",
|
||||
"peaches",
|
||||
"phantom",
|
||||
"pink_lemonade",
|
||||
"pulse",
|
||||
"purpleish",
|
||||
"rainbow_trail",
|
||||
"red_dragon",
|
||||
"red_samurai",
|
||||
"repose_dark",
|
||||
"repose_light",
|
||||
"retro",
|
||||
"retrocast",
|
||||
"rgb",
|
||||
"rose_pine",
|
||||
"rose_pine_dawn",
|
||||
"rose_pine_moon",
|
||||
"rudy",
|
||||
"ryujinscales",
|
||||
"serika",
|
||||
"serika_dark",
|
||||
"sewing_tin",
|
||||
"sewing_tin_light",
|
||||
"shadow",
|
||||
"shoko",
|
||||
"slambook",
|
||||
"snes",
|
||||
"soaring_skies",
|
||||
"solarized_dark",
|
||||
"solarized_light",
|
||||
"solarized_osaka",
|
||||
"sonokai",
|
||||
"stealth",
|
||||
"strawberry",
|
||||
"striker",
|
||||
"suisei",
|
||||
"sunset",
|
||||
"superuser",
|
||||
"sweden",
|
||||
"tangerine",
|
||||
"taro",
|
||||
"terminal",
|
||||
"terra",
|
||||
"terrazzo",
|
||||
"terror_below",
|
||||
"tiramisu",
|
||||
"trackday",
|
||||
"trance",
|
||||
"tron_orange",
|
||||
"vaporwave",
|
||||
"vesper",
|
||||
"viridescent",
|
||||
"voc",
|
||||
"vscode",
|
||||
"watermelon",
|
||||
"wavez",
|
||||
"witch_girl",
|
||||
]);
|
||||
export const ThemeNameSchema = z.enum(
|
||||
[
|
||||
"8008",
|
||||
"80s_after_dark",
|
||||
"9009",
|
||||
"aether",
|
||||
"alduin",
|
||||
"alpine",
|
||||
"anti_hero",
|
||||
"arch",
|
||||
"aurora",
|
||||
"beach",
|
||||
"bento",
|
||||
"bingsu",
|
||||
"bliss",
|
||||
"blue_dolphin",
|
||||
"blueberry_dark",
|
||||
"blueberry_light",
|
||||
"botanical",
|
||||
"bouquet",
|
||||
"breeze",
|
||||
"bushido",
|
||||
"cafe",
|
||||
"camping",
|
||||
"carbon",
|
||||
"catppuccin",
|
||||
"chaos_theory",
|
||||
"cheesecake",
|
||||
"cherry_blossom",
|
||||
"comfy",
|
||||
"copper",
|
||||
"creamsicle",
|
||||
"cy_red",
|
||||
"cyberspace",
|
||||
"dark",
|
||||
"dark_magic_girl",
|
||||
"dark_note",
|
||||
"darling",
|
||||
"deku",
|
||||
"desert_oasis",
|
||||
"dev",
|
||||
"diner",
|
||||
"dino",
|
||||
"discord",
|
||||
"dmg",
|
||||
"dollar",
|
||||
"dots",
|
||||
"dracula",
|
||||
"drowning",
|
||||
"dualshot",
|
||||
"earthsong",
|
||||
"everblush",
|
||||
"evil_eye",
|
||||
"ez_mode",
|
||||
"fire",
|
||||
"fledgling",
|
||||
"fleuriste",
|
||||
"floret",
|
||||
"froyo",
|
||||
"frozen_llama",
|
||||
"fruit_chew",
|
||||
"fundamentals",
|
||||
"future_funk",
|
||||
"github",
|
||||
"godspeed",
|
||||
"graen",
|
||||
"grand_prix",
|
||||
"grape",
|
||||
"gruvbox_dark",
|
||||
"gruvbox_light",
|
||||
"hammerhead",
|
||||
"hanok",
|
||||
"hedge",
|
||||
"honey",
|
||||
"horizon",
|
||||
"husqy",
|
||||
"iceberg_dark",
|
||||
"iceberg_light",
|
||||
"incognito",
|
||||
"ishtar",
|
||||
"iv_clover",
|
||||
"iv_spade",
|
||||
"joker",
|
||||
"laser",
|
||||
"lavender",
|
||||
"leather",
|
||||
"lil_dragon",
|
||||
"lilac_mist",
|
||||
"lime",
|
||||
"luna",
|
||||
"macroblank",
|
||||
"magic_girl",
|
||||
"mashu",
|
||||
"matcha_moccha",
|
||||
"material",
|
||||
"matrix",
|
||||
"menthol",
|
||||
"metaverse",
|
||||
"metropolis",
|
||||
"mexican",
|
||||
"miami",
|
||||
"miami_nights",
|
||||
"midnight",
|
||||
"milkshake",
|
||||
"mint",
|
||||
"mizu",
|
||||
"modern_dolch",
|
||||
"modern_dolch_light",
|
||||
"modern_ink",
|
||||
"monokai",
|
||||
"moonlight",
|
||||
"mountain",
|
||||
"mr_sleeves",
|
||||
"ms_cupcakes",
|
||||
"muted",
|
||||
"nautilus",
|
||||
"nebula",
|
||||
"night_runner",
|
||||
"nord",
|
||||
"nord_light",
|
||||
"norse",
|
||||
"oblivion",
|
||||
"olive",
|
||||
"olivia",
|
||||
"onedark",
|
||||
"our_theme",
|
||||
"paper",
|
||||
"passion_fruit",
|
||||
"pastel",
|
||||
"peach_blossom",
|
||||
"peaches",
|
||||
"phantom",
|
||||
"pink_lemonade",
|
||||
"pulse",
|
||||
"purpleish",
|
||||
"rainbow_trail",
|
||||
"red_dragon",
|
||||
"red_samurai",
|
||||
"repose_dark",
|
||||
"repose_light",
|
||||
"retro",
|
||||
"retrocast",
|
||||
"rgb",
|
||||
"rose_pine",
|
||||
"rose_pine_dawn",
|
||||
"rose_pine_moon",
|
||||
"rudy",
|
||||
"ryujinscales",
|
||||
"serika",
|
||||
"serika_dark",
|
||||
"sewing_tin",
|
||||
"sewing_tin_light",
|
||||
"shadow",
|
||||
"shoko",
|
||||
"slambook",
|
||||
"snes",
|
||||
"soaring_skies",
|
||||
"solarized_dark",
|
||||
"solarized_light",
|
||||
"solarized_osaka",
|
||||
"sonokai",
|
||||
"stealth",
|
||||
"strawberry",
|
||||
"striker",
|
||||
"suisei",
|
||||
"sunset",
|
||||
"superuser",
|
||||
"sweden",
|
||||
"tangerine",
|
||||
"taro",
|
||||
"terminal",
|
||||
"terra",
|
||||
"terrazzo",
|
||||
"terror_below",
|
||||
"tiramisu",
|
||||
"trackday",
|
||||
"trance",
|
||||
"tron_orange",
|
||||
"vaporwave",
|
||||
"vesper",
|
||||
"viridescent",
|
||||
"voc",
|
||||
"vscode",
|
||||
"watermelon",
|
||||
"wavez",
|
||||
"witch_girl",
|
||||
],
|
||||
{
|
||||
errorMap: customEnumErrorHandler("Must be a known theme"),
|
||||
}
|
||||
);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import { z, ZodEffects, ZodOptional, ZodString } from "zod";
|
||||
import { IdSchema, LanguageSchema, StringNumberSchema } from "./util";
|
||||
import { IdSchema, StringNumberSchema } from "./util";
|
||||
import { LanguageSchema } from "./languages";
|
||||
import {
|
||||
ModeSchema,
|
||||
Mode2Schema,
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { z, ZodString } from "zod";
|
||||
import { z, ZodErrorMap, ZodString } from "zod";
|
||||
|
||||
export const StringNumberSchema = z
|
||||
.string()
|
||||
|
|
@ -17,12 +17,6 @@ export type Id = z.infer<typeof IdSchema>;
|
|||
export const TagSchema = token().max(50);
|
||||
export type Tag = z.infer<typeof TagSchema>;
|
||||
|
||||
export const LanguageSchema = z
|
||||
.string()
|
||||
.max(50)
|
||||
.regex(/^[a-zA-Z0-9_+]+$/, "Can only contain letters [a-zA-Z0-9_+]");
|
||||
export type Language = z.infer<typeof LanguageSchema>;
|
||||
|
||||
export const NullableStringSchema = z
|
||||
.string()
|
||||
.nullable()
|
||||
|
|
@ -41,3 +35,12 @@ export type CustomTextMode = z.infer<typeof CustomTextModeSchema>;
|
|||
|
||||
export const CustomTextLimitModeSchema = z.enum(["word", "time", "section"]);
|
||||
export type CustomTextLimitMode = z.infer<typeof CustomTextLimitModeSchema>;
|
||||
|
||||
export function customEnumErrorHandler(message: string): ZodErrorMap {
|
||||
return (issue, _ctx) => ({
|
||||
message:
|
||||
issue.code === "invalid_enum_value"
|
||||
? `Invalid enum value. ${message}`
|
||||
: issue.message ?? "Required",
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,8 @@ import {
|
|||
UserTagSchema,
|
||||
} from "./schemas/users";
|
||||
import { Mode2Schema, ModeSchema, PersonalBestSchema } from "./schemas/shared";
|
||||
import { IdSchema, LanguageSchema, StringNumberSchema } from "./schemas/util";
|
||||
import { IdSchema, StringNumberSchema } from "./schemas/util";
|
||||
import { LanguageSchema } from "./schemas/languages";
|
||||
import { CustomThemeColorsSchema } from "./schemas/configs";
|
||||
import { doesNotContainProfanity } from "./validation/validation";
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue