From 4ee62f57867c8a296e4faa072f8a35ee965704ca Mon Sep 17 00:00:00 2001 From: Lio Young Date: Fri, 9 Jul 2021 15:35:13 +0200 Subject: [PATCH] rewrite lingua entirely lmao --- README.md | 2 + index.ts | 47 ++-- langs/en.yml | 10 +- sample.ts | 6 +- src/de_DE.ts | 62 ------ src/en_US.ts | 24 --- src/types.ts | 331 +++++++++++++++++++++++++++++ langs/template.yml => template.yml | 0 8 files changed, 360 insertions(+), 122 deletions(-) delete mode 100644 src/de_DE.ts delete mode 100644 src/en_US.ts create mode 100644 src/types.ts rename langs/template.yml => template.yml (100%) diff --git a/README.md b/README.md index 8d3eee5..00db6d2 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ # Lingua Language Module for [Thaldrin](https://thaldr.in) + +You can help translate Thaldrin on [GitLocalize](https://gitlocalize.com/repo/6258) diff --git a/index.ts b/index.ts index 7670188..a6af013 100644 --- a/index.ts +++ b/index.ts @@ -1,31 +1,22 @@ -// import en_US from "./src/en_US"; -// import de_DE from "./src/de_DE"; +import yaml from 'js-yaml' +import { readdirSync as readdir, readFileSync as readfile } from "fs"; +import path from "path"; +import { Language } from './src/types'; +export default class Lingua { + #path = './langs' + #langs?: void | string[] + #data?: Language[] = [] -// export default { -// en_US, -// de_DE -// } - -// export default class Lingua { -// constructor() { - -// } -// } - -import jsyaml from 'js-yaml' -// import yaml from 'yaml' - -import fs from 'fs' - - - -try { - const file1 = fs.readFileSync('./langs/1.yml', 'utf8') - const file2 = fs.readFileSync('./langs/2.yml', 'utf8') - const Doc = jsyaml.loadAll(file1) - - console.log(Doc) -} catch (error) { - console.log(error) + constructor() { + this.#langs = readdir(path.join(__dirname, this.#path)).filter(f => f.endsWith('.yml')) ?? [] + // @ts-ignores + this.#langs.forEach(file => this.#data.push(yaml.load(readfile(path.join(__dirname, this.#path, file))))) + } + // @ts-ignore + get(lang: string): Language { + // @ts-ignore + let result: Language = this.#data.find(d => d.meta.locale === lang) + return result + } } \ No newline at end of file diff --git a/langs/en.yml b/langs/en.yml index 6888762..1e4da6c 100644 --- a/langs/en.yml +++ b/langs/en.yml @@ -1,6 +1,6 @@ meta: name: ":flag_us: English (US)" - locale: en_US + locale: en translators: - 318044130796109825 # Lio @@ -38,10 +38,10 @@ categories: name: Misc desc: Miscellaneous Commands fun: - name: fun + name: Fun desc: Fun Commands developer: - name: developer + name: Developer desc: Developer only commands, duh. locale: @@ -68,9 +68,9 @@ user: created: Created joined: Joined states: - online: online + online: Online dnd: Do not Disturb - idle: idle + idle: Idle offline: Offline rp: diff --git a/sample.ts b/sample.ts index 9f5cc62..b036097 100644 --- a/sample.ts +++ b/sample.ts @@ -1,4 +1,4 @@ -// Base File for translations +import Lingua from "."; +let lang = new Lingua() - -// TODO: Enter all strings here \ No newline at end of file +console.log(lang.get("en").missing.mention) \ No newline at end of file diff --git a/src/de_DE.ts b/src/de_DE.ts deleted file mode 100644 index f14827c..0000000 --- a/src/de_DE.ts +++ /dev/null @@ -1,62 +0,0 @@ -export default { - META: { - name: ":flag_de: Deutsch (Deutschland)", - locale: "de_DE", - tranlators: [ - "318044130796109825" // Lio - ] - }, - CHANNEL_NOT_NSFW: "Dieser Channel ist nicht als NSFW markiert, schalte diese Einstellung ein und probier es nochmal.", - INSUFFICIENT_PERMISSIONS: `You need \`PERMISSIONS\` Permissions to run this Command `, - ON_COOLDOWN: `\`COMMAND\` ist grade auf Cooldown.`, - ON_COOLDOWN_DESCRIPTION: `\`COMMAND\` hat einen Cooldown von \`COOLDOWN\` \n Warte \`TIME\` bevor du es noch einmal versuchst.`, - ON_ERROR: `\`COMMAND\` ist ein Fehler unterlaufen.`, - MISSING: { - NOT_ENOUGH_TAGS: `Nicht genug Tags`, - NOT_ENOUGH_TAGS_DESC: "Du musst mir Tags zum suchen geben.", - RP_REQUIRE_MENTION: `Du musst einen anderen Benutzer erwähnen.`, - MISSING_TITLE: `Fehlender Titel. Separiere den Titel und die Beschreibung mit einer "Pipe" (\`|\`)`, - VALUE: { - PREFIX: "Es wurde kein Prefix gegeben.", - COUNTRY: "Kein Länder Code wurde gegeben" - } - }, - - NOT_ENOUGH_TAGS: `Nicht genug Tags`, - NOT_ENOUGH_TAGS_DESC: "Du musst mir Tags zum suchen geben.", - RP_REQUIRE_MENTION: `Du musst einen anderen Benutzer erwähnen.`, - // TODO: change the way the stuff below works or just remove it entirely - RP_SELF: `Don't you want to ACTION someone other than yourself?`, - RP_ME: `Don't ACTION me! ACTION someone else.`, - MISSING_TITLE: `Fehlender Titel. Separiere den Titel und die Beschreibung mit einer "Pipe" (\`|\`).`, - SUGGESTION_SENT: "Vorschlag abgeschickt.", - INVITE_STRING: "Du kannst BOT mit diesem Link einladen", - ROLL: ":game_die: Werfe AMOUNT DICE Würfel...", - CATEGORIES: { - INFO: { name: "Info", desc: "" }, - NSFW: { name: ":underage: NSFW", desc: "Horny Stuff, natürlich." }, - ANIMALS: { name: "Tiere", desc: "Süße Tierbilder um dir den Tag zu verschönern!" }, - MISC: { name: "Misc", desc: "Miscellaneous Commands" }, - FUN: { name: "Spaß", desc: "" }, - DEVELOPER: { name: "Entwickler", desc: "Developer only Commands, duh" }, - }, - DEVELOPER_ONLY: "Dieser Befehl ist nur für Entwickler.", - MISC: { - ENABLED: "An", - DISABLED: "Aus", - }, - LOCALE: { - LANGUAGE: "Sprache", - CONTRIBUTORS: "AMOUNT Übersetzer", - TITLE: "LANGUAGE von TRANSLATOR", - COMMAND_DESC: "BOT ist in AMOUNT Sprachen verfügbar, du kannst ganz einfach BOT's Sprache ändern indem du `PREFIX locale set ` in den Chat schickst\n\n[Übersetzungen](https://t8.pm/lingua) wird durch Hilfe der Community bereitgestellt.", - UPDATED_SETTING: 'Updated SETTING to VALUE', - UNSUPPORTED: "BOT unterstützt VALUE grade nicht.", - DEFAULT: { - LANGUAGES: "Sprachen", - LOCALIZATION: "Lokalisierung", - CURRENT: `Jetzige Sprache`, - SUB: `• Benutz \`PREFIX locale set \` um die Sprache des Server's zu ändern` - } - } -} \ No newline at end of file diff --git a/src/en_US.ts b/src/en_US.ts deleted file mode 100644 index 5b9f4cf..0000000 --- a/src/en_US.ts +++ /dev/null @@ -1,24 +0,0 @@ -export default { - META: { - name: ":flag_us: English (US)", - locale: "en_US", - tranlators: [ - "318044130796109825" // Lio - ] - - }, - MISSING: { - NOT_ENOUGH_TAGS: `Not Enough Tags`, - NOT_ENOUGH_TAGS_DESC: "You need to provide a few Tags for me to search for.", - RP_REQUIRE_MENTION: `You need to mention another user.`, - MISSING_TITLE: `Missing title. Separate the title and description with a pipe (\`|\`).`, - VALUE: { - PREFIX: "No Prefix was given.", - COUNTRY: "No Country code was given", - SETTING: "No Setting was given." - } - }, - RP_SELF: `Don't you want to ACTION someone other than yourself?`, - RP_ME: `Don't ACTION me! ACTION someone else.`, - -} \ No newline at end of file diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..07ed67f --- /dev/null +++ b/src/types.ts @@ -0,0 +1,331 @@ +// To parse this data: +// +// import { Convert, Language } from "./file"; +// +// const language = Convert.toLanguage(json); +// +// These functions will throw an error if the JSON doesn't +// match the expected interface, even if the JSON is valid. + +export interface Language { + meta: Meta; + missing: Missing; + error: Error; + categories: Categories; + locale: Locale; + misc: Misc; + user: User; + rp: Rp; +} + +export interface Categories { + info: Command; + nsfw: Command; + animals: Command; + misc: Command; + fun: Command; + developer: Command; +} + +export interface Command { + name: string; + desc: string; +} + +export interface Error { + nsfw: string; + permissions: string; + error: string; + cooldown: Command; + developer: string; +} + +export interface Locale { + language: string; + translators: string; + title: string; + amount: string; + updated: string; + unsupported: string; +} + +export interface Meta { + name: string; + locale: string; + translators: number[]; +} + +export interface Misc { + invite: string; + roll: string; + sent: string; + enabled: string; + disabled: string; +} + +export interface Missing { + tags: Command; + values: Values; + title: string; + mention: string; +} + +export interface Values { + prefix: string; + country: string; + setting: string; +} + +export interface Rp { + client: string; + self: string; +} + +export interface User { + info: string; + status: string; + roles: string; + username: string; + id: string; + created: string; + joined: string; + states: States; +} + +export interface States { + online: string; + dnd: string; + idle: string; + offline: string; +} + +// Converts JSON strings to/from your types +// and asserts the results of JSON.parse at runtime +export class Convert { + public static toLanguage(json: string): Language { + return cast(JSON.parse(json), r("Language")); + } + + public static languageToJson(value: Language): string { + return JSON.stringify(uncast(value, r("Language")), null, 2); + } +} + +function invalidValue(typ: any, val: any, key: any = ''): never { + if (key) { + throw Error(`Invalid value for key "${key}". Expected type ${JSON.stringify(typ)} but got ${JSON.stringify(val)}`); + } + throw Error(`Invalid value ${JSON.stringify(val)} for type ${JSON.stringify(typ)}`,); +} + +function jsonToJSProps(typ: any): any { + if (typ.jsonToJS === undefined) { + const map: any = {}; + typ.props.forEach((p: any) => map[p.json] = { key: p.js, typ: p.typ }); + typ.jsonToJS = map; + } + return typ.jsonToJS; +} + +function jsToJSONProps(typ: any): any { + if (typ.jsToJSON === undefined) { + const map: any = {}; + typ.props.forEach((p: any) => map[p.js] = { key: p.json, typ: p.typ }); + typ.jsToJSON = map; + } + return typ.jsToJSON; +} + +function transform(val: any, typ: any, getProps: any, key: any = ''): any { + function transformPrimitive(typ: string, val: any): any { + if (typeof typ === typeof val) return val; + return invalidValue(typ, val, key); + } + + function transformUnion(typs: any[], val: any): any { + // val must validate against one typ in typs + const l = typs.length; + for (let i = 0; i < l; i++) { + const typ = typs[i]; + try { + return transform(val, typ, getProps); + } catch (_) { } + } + return invalidValue(typs, val); + } + + function transformEnum(cases: string[], val: any): any { + if (cases.indexOf(val) !== -1) return val; + return invalidValue(cases, val); + } + + function transformArray(typ: any, val: any): any { + // val must be an array with no invalid elements + if (!Array.isArray(val)) return invalidValue("array", val); + return val.map(el => transform(el, typ, getProps)); + } + + function transformDate(val: any): any { + if (val === null) { + return null; + } + const d = new Date(val); + if (isNaN(d.valueOf())) { + return invalidValue("Date", val); + } + return d; + } + + function transformObject(props: { [k: string]: any }, additional: any, val: any): any { + if (val === null || typeof val !== "object" || Array.isArray(val)) { + return invalidValue("object", val); + } + const result: any = {}; + Object.getOwnPropertyNames(props).forEach(key => { + const prop = props[key]; + const v = Object.prototype.hasOwnProperty.call(val, key) ? val[key] : undefined; + result[prop.key] = transform(v, prop.typ, getProps, prop.key); + }); + Object.getOwnPropertyNames(val).forEach(key => { + if (!Object.prototype.hasOwnProperty.call(props, key)) { + result[key] = transform(val[key], additional, getProps, key); + } + }); + return result; + } + + if (typ === "any") return val; + if (typ === null) { + if (val === null) return val; + return invalidValue(typ, val); + } + if (typ === false) return invalidValue(typ, val); + while (typeof typ === "object" && typ.ref !== undefined) { + typ = typeMap[typ.ref]; + } + if (Array.isArray(typ)) return transformEnum(typ, val); + if (typeof typ === "object") { + return typ.hasOwnProperty("unionMembers") ? transformUnion(typ.unionMembers, val) + : typ.hasOwnProperty("arrayItems") ? transformArray(typ.arrayItems, val) + : typ.hasOwnProperty("props") ? transformObject(getProps(typ), typ.additional, val) + : invalidValue(typ, val); + } + // Numbers can be parsed by Date but shouldn't be. + if (typ === Date && typeof val !== "number") return transformDate(val); + return transformPrimitive(typ, val); +} + +function cast(val: any, typ: any): T { + return transform(val, typ, jsonToJSProps); +} + +function uncast(val: T, typ: any): any { + return transform(val, typ, jsToJSONProps); +} + +function a(typ: any) { + return { arrayItems: typ }; +} + +function u(...typs: any[]) { + return { unionMembers: typs }; +} + +function o(props: any[], additional: any) { + return { props, additional }; +} + +function m(additional: any) { + return { props: [], additional }; +} + +function r(name: string) { + return { ref: name }; +} + +const typeMap: any = { + "Language": o([ + { json: "meta", js: "meta", typ: r("Meta") }, + { json: "missing", js: "missing", typ: r("Missing") }, + { json: "error", js: "error", typ: r("Error") }, + { json: "categories", js: "categories", typ: r("Categories") }, + { json: "locale", js: "locale", typ: r("Locale") }, + { json: "misc", js: "misc", typ: r("Misc") }, + { json: "user", js: "user", typ: r("User") }, + { json: "rp", js: "rp", typ: r("Rp") }, + ], false), + "Categories": o([ + { json: "info", js: "info", typ: r("Command") }, + { json: "nsfw", js: "nsfw", typ: r("Command") }, + { json: "animals", js: "animals", typ: r("Command") }, + { json: "misc", js: "misc", typ: r("Command") }, + { json: "fun", js: "fun", typ: r("Command") }, + { json: "developer", js: "developer", typ: r("Command") }, + ], false), + "Command": o([ + { json: "name", js: "name", typ: "" }, + { json: "desc", js: "desc", typ: "" }, + ], false), + "Error": o([ + { json: "nsfw", js: "nsfw", typ: "" }, + { json: "permissions", js: "permissions", typ: "" }, + { json: "error", js: "error", typ: "" }, + { json: "Cooldown", js: "Cooldown", typ: r("Command") }, + { json: "developer", js: "developer", typ: "" }, + ], false), + "Cooldown": o([ + { json: "title", js: "title", typ: "" }, + { json: "desc", js: "desc", typ: "" }, + ], false), + "Locale": o([ + { json: "language", js: "language", typ: "" }, + { json: "translators", js: "translators", typ: "" }, + { json: "title", js: "title", typ: "" }, + { json: "amount", js: "amount", typ: "" }, + { json: "updated", js: "updated", typ: "" }, + { json: "unsupported", js: "unsupported", typ: "" }, + ], false), + "Meta": o([ + { json: "name", js: "name", typ: "" }, + { json: "locale", js: "locale", typ: "" }, + { json: "translators", js: "translators", typ: a(3.14) }, + ], false), + "Misc": o([ + { json: "invite", js: "invite", typ: "" }, + { json: "roll", js: "roll", typ: "" }, + { json: "sent", js: "sent", typ: "" }, + { json: "enabled", js: "enabled", typ: "" }, + { json: "disabled", js: "disabled", typ: "" }, + ], false), + "Missing": o([ + { json: "tags", js: "tags", typ: r("Command") }, + { json: "values", js: "values", typ: r("Values") }, + { json: "title", js: "title", typ: "" }, + { json: "mention", js: "mention", typ: "" }, + ], false), + "Values": o([ + { json: "prefix", js: "prefix", typ: "" }, + { json: "country", js: "country", typ: "" }, + { json: "setting", js: "setting", typ: "" }, + ], false), + "Rp": o([ + { json: "client", js: "client", typ: "" }, + { json: "self", js: "self", typ: "" }, + ], false), + "User": o([ + { json: "info", js: "info", typ: "" }, + { json: "status", js: "status", typ: "" }, + { json: "roles", js: "roles", typ: "" }, + { json: "username", js: "username", typ: "" }, + { json: "id", js: "id", typ: "" }, + { json: "created", js: "created", typ: "" }, + { json: "joined", js: "joined", typ: "" }, + { json: "states", js: "states", typ: r("States") }, + ], false), + "States": o([ + { json: "online", js: "online", typ: "" }, + { json: "dnd", js: "dnd", typ: "" }, + { json: "idle", js: "idle", typ: "" }, + { json: "offline", js: "offline", typ: "" }, + ], false), +}; diff --git a/langs/template.yml b/template.yml similarity index 100% rename from langs/template.yml rename to template.yml