From 1e17fe18f864ba5f6480a8660c72eb577d5cfd27 Mon Sep 17 00:00:00 2001 From: Egor Gorbachev <7gorbachevm@gmail.com> Date: Thu, 28 Dec 2023 22:30:41 +0700 Subject: [PATCH] Add multiple cards in one go (#31) * Add multiple cards in one go --- .../db/user/user-set-server-bot-state.ts | 27 ++++- functions/server-bot/callback-query-type.ts | 1 + functions/server-bot/on-callback-query.ts | 68 ++++++++++--- functions/server-bot/on-message.ts | 39 +++++--- functions/server-bot/parse-cards-from-text.ts | 31 ++++++ .../server-bot/parse-deck-from-text.test.ts | 99 ++++++++++++++++--- functions/server-bot/parse-deck-from-text.ts | 21 ---- functions/server-bot/render-field-value.ts | 9 ++ .../render-many-cards-to-create.test.ts | 40 ++++++++ .../server-bot/render-many-cards-to-create.ts | 25 +++++ .../send-card-create-confirm-message.ts | 31 ++---- ...d-multiple-cards-create-confirm-message.ts | 43 ++++++++ functions/translations/create-translator.ts | 57 ++++++++--- 13 files changed, 395 insertions(+), 96 deletions(-) create mode 100644 functions/server-bot/parse-cards-from-text.ts delete mode 100644 functions/server-bot/parse-deck-from-text.ts create mode 100644 functions/server-bot/render-field-value.ts create mode 100644 functions/server-bot/render-many-cards-to-create.test.ts create mode 100644 functions/server-bot/render-many-cards-to-create.ts create mode 100644 functions/server-bot/send-multiple-cards-create-confirm-message.ts diff --git a/functions/db/user/user-set-server-bot-state.ts b/functions/db/user/user-set-server-bot-state.ts index 4984580e..354ba0eb 100644 --- a/functions/db/user/user-set-server-bot-state.ts +++ b/functions/db/user/user-set-server-bot-state.ts @@ -4,8 +4,33 @@ import { DatabaseException } from "../database-exception.ts"; export type ServerBotState = | null - | { type: "cardAdded"; cardFront: string; cardBack: string } | { + // better name - cardGiven + type: "cardAdded"; + cardFront: string; + cardBack: string; + cardExample: string | null; + } + | { + // better name - manyCardsGiven + type: "manyCardsAdded"; + cards: Array<{ + cardFront: string; + cardBack: string; + cardExample: string | null; + }>; + } + | { + type: "deckWithManyCardsSelected"; + deckId: number; + cards: Array<{ + cardFront: string; + cardBack: string; + cardExample: string | null; + }>; + } + | { + // deck with only 1 card type: "deckSelected"; cardFront: string; cardBack: string; diff --git a/functions/server-bot/callback-query-type.ts b/functions/server-bot/callback-query-type.ts index 79b50daf..4f56bf38 100644 --- a/functions/server-bot/callback-query-type.ts +++ b/functions/server-bot/callback-query-type.ts @@ -1,6 +1,7 @@ export enum CallbackQueryType { Deck = "deck", ConfirmCreateCard = "confirm", + ConfirmCreateManyCards = "confirm-many-cards", EditFront = "edit-front", EditExample = "edit-example", EditBack = "edit-back", diff --git a/functions/server-bot/on-callback-query.ts b/functions/server-bot/on-callback-query.ts index 1f90b59b..b04de75d 100644 --- a/functions/server-bot/on-callback-query.ts +++ b/functions/server-bot/on-callback-query.ts @@ -11,6 +11,7 @@ import { sendCardCreateConfirmMessage } from "./send-card-create-confirm-message import { DatabaseException } from "../db/database-exception.ts"; import { createUserAwareTranslator } from "../translations/create-user-aware-translator.ts"; import { MemoCardTranslator } from "../translations/create-translator.ts"; +import { sendMultipleCardsCreateConfirmMessage } from "./send-multiple-cards-create-confirm-message.ts"; type CallbackQueryEdit = | CallbackQueryType.EditFront @@ -51,32 +52,49 @@ export const onCallbackQuery = (envSafe: EnvSafe) => async (ctx: Context) => { assert(ctx.from); const data = ctx.callbackQuery.data; - const db = getDatabase(envSafe); if (!data) { await ctx.answerCallbackQuery(); return; } + const db = getDatabase(envSafe); const translator = await createUserAwareTranslator(envSafe, ctx); - if (data.startsWith(CallbackQueryType.Deck)) { + if (data.startsWith(`${CallbackQueryType.Deck}:`)) { const deckId = Number(data.split(":")[1]); if (!deckId) { throw new Error(`Deck id ${deckId} is not valid`); } const state = await userGetServerBotState(envSafe, ctx.from.id); - if (state?.type !== "cardAdded") { + if ( + !state || + (state.type !== "cardAdded" && state.type !== "manyCardsAdded") + ) { return; } - await userSetServerBotState(envSafe, ctx.from.id, { - type: "deckSelected", - cardBack: state.cardBack, - cardFront: state.cardFront, - cardExample: null, - deckId, - }); - await sendCardCreateConfirmMessage(envSafe, ctx); + if (state.type === "cardAdded") { + await userSetServerBotState(envSafe, ctx.from.id, { + type: "deckSelected", + cardBack: state.cardBack, + cardFront: state.cardFront, + cardExample: state.cardExample, + deckId, + }); + + await sendCardCreateConfirmMessage(envSafe, ctx, translator); + } + + if (state.type === "manyCardsAdded") { + await userSetServerBotState(envSafe, ctx.from.id, { + type: "deckWithManyCardsSelected", + cards: state.cards, + deckId, + }); + + await sendMultipleCardsCreateConfirmMessage(envSafe, ctx, translator); + } + await ctx.answerCallbackQuery(); return; } @@ -121,7 +139,33 @@ export const onCallbackQuery = (envSafe: EnvSafe) => async (ctx: Context) => { throw new DatabaseException(createCardsResult.error); } - await ctx.reply(translator.translate("card_created")); + await ctx.reply(`${translator.translate("card_created")}`); + await ctx.deleteMessage(); + await userSetServerBotState(envSafe, ctx.from.id, null); + return; + } + + if (data === CallbackQueryType.ConfirmCreateManyCards) { + const state = await userGetServerBotState(envSafe, ctx.from.id); + assert( + state?.type === "deckWithManyCardsSelected", + "State is not deckWithManyCardsSelected", + ); + + const createCardsResult = await db.from("deck_card").insert( + state.cards.map((card) => ({ + deck_id: state.deckId, + front: card.cardFront, + back: card.cardBack, + example: card.cardExample, + })), + ); + + if (createCardsResult.error) { + throw new DatabaseException(createCardsResult.error); + } + + await ctx.reply(translator.translate("many_cards_created")); await ctx.deleteMessage(); await userSetServerBotState(envSafe, ctx.from.id, null); return; diff --git a/functions/server-bot/on-message.ts b/functions/server-bot/on-message.ts index 6bf63b59..c843dde2 100644 --- a/functions/server-bot/on-message.ts +++ b/functions/server-bot/on-message.ts @@ -6,7 +6,7 @@ import { userSetServerBotState, } from "../db/user/user-set-server-bot-state.ts"; import { sendCardCreateConfirmMessage } from "./send-card-create-confirm-message.ts"; -import { parseDeckFromText } from "./parse-deck-from-text.ts"; +import { parseCardsFromText } from "./parse-cards-from-text.ts"; import { getDecksCreatedByMe } from "../db/deck/get-decks-created-by-me.ts"; import { CallbackQueryType } from "./callback-query-type.ts"; import { createUserAwareTranslator } from "../translations/create-user-aware-translator.ts"; @@ -28,13 +28,12 @@ export const onMessage = (envSafe: EnvSafe) => async (ctx: Context) => { editingField: undefined, }); - await sendCardCreateConfirmMessage(envSafe, ctx); - + await sendCardCreateConfirmMessage(envSafe, ctx, translator); return; } - const cardAsText = parseDeckFromText(ctx.message.text); - if (!cardAsText) { + const cardsParsed = parseCardsFromText(ctx.message.text); + if (!cardsParsed.length) { await ctx.reply(translator.translate("invalid_card_format"), { parse_mode: "MarkdownV2", }); @@ -42,7 +41,7 @@ export const onMessage = (envSafe: EnvSafe) => async (ctx: Context) => { } const decks = await getDecksCreatedByMe(envSafe, ctx.from.id); - if (decks.length === 0) { + if (!decks.length) { await ctx.reply(translator.translate("no_decks_created"), { reply_markup: new InlineKeyboard().url( translator.translate("create_deck"), @@ -52,13 +51,29 @@ export const onMessage = (envSafe: EnvSafe) => async (ctx: Context) => { return; } - await userSetServerBotState(envSafe, ctx.from.id, { - type: "cardAdded", - cardFront: cardAsText.front, - cardBack: cardAsText.back, - }); + let message = ""; + if (cardsParsed.length === 1) { + const cardParsed = cardsParsed[0]; + await userSetServerBotState(envSafe, ctx.from.id, { + type: "cardAdded", + cardFront: cardParsed.front, + cardBack: cardParsed.back, + cardExample: cardParsed.example || null, + }); + message = translator.translate("create_card_from_deck_message"); + } else { + await userSetServerBotState(envSafe, ctx.from.id, { + type: "manyCardsAdded", + cards: cardsParsed.map((cardParsed) => ({ + cardFront: cardParsed.front, + cardBack: cardParsed.back, + cardExample: cardParsed.example || null, + })), + }); + message = translator.translate("create_many_cards_message"); + } - await ctx.reply(translator.translate("create_card_from_deck_message"), { + await ctx.reply(message, { reply_markup: InlineKeyboard.from( decks .map((deck) => [ diff --git a/functions/server-bot/parse-cards-from-text.ts b/functions/server-bot/parse-cards-from-text.ts new file mode 100644 index 00000000..ebed64b3 --- /dev/null +++ b/functions/server-bot/parse-cards-from-text.ts @@ -0,0 +1,31 @@ +const fieldSeparator = " - "; +const deckSeparator = "\n"; +// deckSeparator as regex one or many new lines +const deckSeparatorRegex = /\n+/g; + +type CardParsed = { + front: string; + back: string; + example?: string; +}; + +export const parseCardsFromText = (text: string): Array => { + if (!text.includes(deckSeparator)) { + return [extractDeckFromRow(text)]; + } + + const rows = text.split(deckSeparatorRegex); + + return rows.map(extractDeckFromRow); +}; + +const extractDeckFromRow = (row: string): CardParsed => { + const [front, back, example] = row.split(fieldSeparator); + if (!front || !back) { + return { + front: row, + back: row, + }; + } + return { front, back, example }; +}; diff --git a/functions/server-bot/parse-deck-from-text.test.ts b/functions/server-bot/parse-deck-from-text.test.ts index d1abc85d..3405197b 100644 --- a/functions/server-bot/parse-deck-from-text.test.ts +++ b/functions/server-bot/parse-deck-from-text.test.ts @@ -1,19 +1,92 @@ import { expect, test } from "vitest"; -import { parseDeckFromText } from "./parse-deck-from-text.ts"; +import { parseCardsFromText } from "./parse-cards-from-text.ts"; test("parse deck from text", () => { - expect(parseDeckFromText("front - back")).toEqual({ - front: "front", - back: "back", - }); + expect(parseCardsFromText("front - back")).toEqual([ + { + front: "front", + back: "back", + example: undefined, + }, + ]); - expect(parseDeckFromText("front - back - test")).toEqual({ - front: "front", - back: "back", - }); + expect(parseCardsFromText("front - back - test")).toEqual([ + { + front: "front", + back: "back", + example: "test", + }, + ]); - expect(parseDeckFromText("one side")).toEqual({ - front: "one side", - back: "one side", - }); + expect(parseCardsFromText("one side")).toEqual([ + { + front: "one side", + back: "one side", + example: undefined, + }, + ]); + + expect(parseCardsFromText("one side\na\nb")).toEqual([ + { + front: "one side", + back: "one side", + example: undefined, + }, + { + front: "a", + back: "a", + }, + { + front: "b", + back: "b", + }, + ]); + + expect( + parseCardsFromText("front - back\na - b - c\nd - e\nk - n - m"), + ).toEqual([ + { + front: "front", + back: "back", + example: undefined, + }, + { + front: "a", + back: "b", + example: "c", + }, + { + front: "d", + back: "e", + }, + { + front: "k", + back: "n", + example: "m", + }, + ]); + + expect( + parseCardsFromText("front - back\n\n\na - b - c\n\nd - e\nk - n - m"), + ).toEqual([ + { + front: "front", + back: "back", + example: undefined, + }, + { + front: "a", + back: "b", + example: "c", + }, + { + front: "d", + back: "e", + }, + { + front: "k", + back: "n", + example: "m", + }, + ]); }); diff --git a/functions/server-bot/parse-deck-from-text.ts b/functions/server-bot/parse-deck-from-text.ts deleted file mode 100644 index 3a1cfb72..00000000 --- a/functions/server-bot/parse-deck-from-text.ts +++ /dev/null @@ -1,21 +0,0 @@ -const separator = " - "; - -export const parseDeckFromText = ( - text: string, -): { - front: string; - back: string; -} | null => { - if (!text.includes(separator)) { - return { - front: text, - back: text, - }; - } - - const [front, back] = text.split(separator); - if (!front || !back) { - return null; - } - return { front, back }; -}; diff --git a/functions/server-bot/render-field-value.ts b/functions/server-bot/render-field-value.ts new file mode 100644 index 00000000..3faa15ef --- /dev/null +++ b/functions/server-bot/render-field-value.ts @@ -0,0 +1,9 @@ +import { escapeMarkdown } from "./escape-markdown.ts"; + +export const renderFieldValue = (value: string | null) => { + if (!value) { + return "_None_"; + } + + return escapeMarkdown(value); +}; diff --git a/functions/server-bot/render-many-cards-to-create.test.ts b/functions/server-bot/render-many-cards-to-create.test.ts new file mode 100644 index 00000000..9409be01 --- /dev/null +++ b/functions/server-bot/render-many-cards-to-create.test.ts @@ -0,0 +1,40 @@ +import { expect, test } from "vitest"; +import { renderManyCardsToCreate } from "./render-many-cards-to-create.ts"; + +test("render-many-cards-to-create", async () => { + const translator = { + translate: (key: string) => key, + } as any; + + expect(renderManyCardsToCreate([], translator)).toMatchInlineSnapshot( + '"confirm_many_cards_creation"', + ); + + expect( + renderManyCardsToCreate( + [ + { + cardFront: "front", + cardBack: "back", + cardExample: "example", + }, + { + cardFront: "a", + cardBack: "b", + cardExample: "c", + }, + ], + translator, + ), + ).toMatchInlineSnapshot(` + "confirm_many_cards_creation + + *1*\\\\. *confirm_many_cards_front* front + *confirm_many_cards_back* back + *confirm_many_cards_example* example + + *2*\\\\. *confirm_many_cards_front* a + *confirm_many_cards_back* b + *confirm_many_cards_example* c" + `); +}); diff --git a/functions/server-bot/render-many-cards-to-create.ts b/functions/server-bot/render-many-cards-to-create.ts new file mode 100644 index 00000000..74a834cd --- /dev/null +++ b/functions/server-bot/render-many-cards-to-create.ts @@ -0,0 +1,25 @@ +import { MemoCardTranslator } from "../translations/create-translator.ts"; +import { renderFieldValue } from "./render-field-value.ts"; + +export const renderManyCardsToCreate = ( + cards: Array<{ + cardFront: string; + cardBack: string; + cardExample: string | null; + }>, + translator: MemoCardTranslator, +) => { + let message = translator.translate("confirm_many_cards_creation"); + for (let i = 0; i < cards.length; i++) { + message += `\n\n*${i + 1}*${renderFieldValue(".")} *${translator.translate( + "confirm_many_cards_front", + )}* ${renderFieldValue(cards[i].cardFront)}`; + message += `\n*${translator.translate( + "confirm_many_cards_back", + )}* ${renderFieldValue(cards[i].cardBack)}`; + message += `\n*${translator.translate( + "confirm_many_cards_example", + )}* ${renderFieldValue(cards[i].cardExample)}`; + } + return message; +}; diff --git a/functions/server-bot/send-card-create-confirm-message.ts b/functions/server-bot/send-card-create-confirm-message.ts index d80f2d90..c39d9459 100644 --- a/functions/server-bot/send-card-create-confirm-message.ts +++ b/functions/server-bot/send-card-create-confirm-message.ts @@ -1,38 +1,21 @@ import { EnvSafe } from "../env/env-schema.ts"; import { Context, InlineKeyboard } from "grammy"; import { assert } from "../lib/typescript/assert.ts"; -import { - userGetServerBotState, - userSetServerBotState, -} from "../db/user/user-set-server-bot-state.ts"; +import { userGetServerBotState } from "../db/user/user-set-server-bot-state.ts"; import { CallbackQueryType } from "./callback-query-type.ts"; -import { escapeMarkdown } from "./escape-markdown.ts"; -import { createUserAwareTranslator } from "../translations/create-user-aware-translator.ts"; - -const renderFieldValue = (value: string | null) => { - if (!value) { - return "_None_"; - } - - return escapeMarkdown(value); -}; +import { renderFieldValue } from "./render-field-value.ts"; +import { MemoCardTranslator } from "../translations/create-translator.ts"; export const sendCardCreateConfirmMessage = async ( envSafe: EnvSafe, ctx: Context, + translator: MemoCardTranslator, ) => { assert(ctx.from); - const translator = await createUserAwareTranslator(envSafe, ctx); const state = await userGetServerBotState(envSafe, ctx.from.id); - assert(state?.type === "deckSelected"); - - await userSetServerBotState(envSafe, ctx.from.id, { - type: "deckSelected", - cardBack: state.cardBack, - cardFront: state.cardFront, - deckId: state.deckId, - cardExample: state.cardExample, - }); + if (state?.type !== "deckSelected") { + return; + } await ctx.deleteMessage(); diff --git a/functions/server-bot/send-multiple-cards-create-confirm-message.ts b/functions/server-bot/send-multiple-cards-create-confirm-message.ts new file mode 100644 index 00000000..52ff3965 --- /dev/null +++ b/functions/server-bot/send-multiple-cards-create-confirm-message.ts @@ -0,0 +1,43 @@ +import { EnvSafe } from "../env/env-schema.ts"; +import { Context, InlineKeyboard } from "grammy"; +import { assert } from "../lib/typescript/assert.ts"; +import { userGetServerBotState } from "../db/user/user-set-server-bot-state.ts"; +import { CallbackQueryType } from "./callback-query-type.ts"; +import { MemoCardTranslator } from "../translations/create-translator.ts"; +import { renderManyCardsToCreate } from "./render-many-cards-to-create.ts"; + +export const sendMultipleCardsCreateConfirmMessage = async ( + envSafe: EnvSafe, + ctx: Context, + translator: MemoCardTranslator, +) => { + assert(ctx.from); + const state = await userGetServerBotState(envSafe, ctx.from.id); + if (state?.type !== "deckWithManyCardsSelected") { + return; + } + + await ctx.deleteMessage(); + if (state.cards.length === 0) { + await ctx.reply(translator.translate("no_cards_to_create")); + return; + } + + const message = renderManyCardsToCreate(state.cards, translator); + + await ctx.reply(message, { + parse_mode: "MarkdownV2", + reply_markup: InlineKeyboard.from([ + [ + InlineKeyboard.text( + translator.translate("bot_button_cancel"), + CallbackQueryType.Cancel, + ), + InlineKeyboard.text( + translator.translate("bot_button_confirm"), + CallbackQueryType.ConfirmCreateManyCards, + ), + ], + ]), + }); +}; diff --git a/functions/translations/create-translator.ts b/functions/translations/create-translator.ts index 61fc8a1f..c9b94667 100644 --- a/functions/translations/create-translator.ts +++ b/functions/translations/create-translator.ts @@ -8,19 +8,26 @@ const en = { create_deck: "Create deck", create_card_from_deck_message: "To create a card from the text, select a deck: ", + create_many_cards_message: "To create cards from the text, select a deck:", bot_button_cancel: "❌ Cancel", bot_button_confirm: "✅ Create", bot_button_edit_front: `✏️ Front`, bot_button_edit_back: `✏️ Back`, bot_button_edit_example: `✏️ Edit example`, cancelled: "Cancelled", - card_created: "Card has been created", + card_created: "Card has been created 🎉", send_new_front: "Send a message with the new front", send_new_back: "Send a message with the new back", send_new_example: "Send a message with the new example", confirm_card_creation_front: `Create card?\n\n*Front:* `, - confirm_card_creation_back: `\n\n*Back:* `, - confirm_card_creation_example: `\n\n*Example:* `, + confirm_many_cards_creation: `Create these cards? You will be able to edit them in the app after creation`, + confirm_many_cards_front: "Front:", + confirm_many_cards_back: "Back:", + confirm_many_cards_example: "Example:", + confirm_card_creation_back: `\n*Back:* `, + confirm_card_creation_example: `\n*Example:* `, + no_cards_to_create: "No cards to create", + many_cards_created: "Cards have been created 🎉", start_button: "Start bot", }; @@ -34,9 +41,11 @@ const ru: Translation = { create_deck: "Создать колоду", create_card_from_deck_message: "Чтобы создать карточку из этого текста, выбери колоду: ", + create_many_cards_message: + "Чтобы создать карточки из этого текста, выбери колоду:", bot_button_cancel: "❌ Отмена", cancelled: "Отменено", - card_created: "Карточка создана", + card_created: "Карточка создана 🎉", send_new_front: "Отправь сообщение с новым вопросом", send_new_back: "Отправь сообщение с новым ответом", send_new_example: "Отправь сообщение с новым примером", @@ -44,9 +53,15 @@ const ru: Translation = { bot_button_edit_back: `✏️ Ответ`, bot_button_edit_example: `✏️ Пример`, bot_button_edit_front: `✏️ Вопрос`, - confirm_card_creation_back: `\n\n*Ответ:* `, - confirm_card_creation_example: `\n\n*Пример:* `, + confirm_card_creation_back: `\n*Ответ:* `, + confirm_card_creation_example: `\n*Пример:* `, confirm_card_creation_front: `Создать карточку?:\n\n*Вопрос:* `, + confirm_many_cards_creation: `Создать эти карточки? Ты сможешь отредактировать их в приложении после создания`, + confirm_many_cards_front: "Вопрос:", + confirm_many_cards_back: "Ответ:", + confirm_many_cards_example: "Пример:", + many_cards_created: "Карточки созданы 🎉", + no_cards_to_create: "Нет карточек для создания", start_button: "Запустить бота", }; @@ -59,19 +74,27 @@ const es: Translation = { create_deck: "Crear mazo", create_card_from_deck_message: "Para crear una tarjeta a partir de este texto, seleccione un mazo: ", + create_many_cards_message: + "Para crear tarjetas a partir de este texto, seleccione un mazo:", bot_button_cancel: "❌ Cancelar", cancelled: "Cancelado", - card_created: "La tarjeta ha sido creada", + card_created: "La tarjeta ha sido creada 🎉", send_new_front: "Enviar un mensaje con la nueva pregunta", send_new_back: "Enviar un mensaje con la nueva respuesta", send_new_example: "Enviar un mensaje con el nuevo ejemplo", - confirm_card_creation_back: `\n\n*Respuesta:* `, + confirm_card_creation_back: `\n*Respuesta:* `, bot_button_edit_front: `✏️ Pregunta`, bot_button_edit_example: `✏️ Ejemplo`, bot_button_edit_back: `✏️ Respuesta`, bot_button_confirm: "✅ Crear", - confirm_card_creation_example: `\n\n*Ejemplo:* `, + confirm_card_creation_example: `\n*Ejemplo:* `, + confirm_many_cards_creation: `Crear estas tarjetas? Podrás editarlos en la aplicación después de su creación`, confirm_card_creation_front: `Crear tarjeta?:\n\n*Pregunta:* `, + confirm_many_cards_front: "Pregunta:", + confirm_many_cards_back: "Respuesta:", + confirm_many_cards_example: "Ejemplo:", + many_cards_created: "Tarjetas creadas 🎉", + no_cards_to_create: "No hay tarjetas para crear", start_button: "Iniciar bot", }; @@ -84,9 +107,11 @@ const ptBr: Translation = { create_deck: "Criar baralho", create_card_from_deck_message: "Para criar um cartão a partir deste texto, selecione um baralho: ", + create_many_cards_message: + "Para criar cartões a partir deste texto, selecione um baralho:", bot_button_cancel: "❌ Cancelar", cancelled: "Cancelado", - card_created: "Cartão criado", + card_created: "Cartão criado 🎉", send_new_front: "Envie uma mensagem com a nova pergunta", send_new_back: "Envie uma mensagem com a nova resposta", send_new_example: "Envie uma mensagem com o novo exemplo", @@ -94,9 +119,15 @@ const ptBr: Translation = { bot_button_edit_back: `✏️ Resposta`, bot_button_edit_example: `✏️ Exemplo`, bot_button_edit_front: `✏️ Pergunta`, - confirm_card_creation_back: `\n\n*Resposta:* `, - confirm_card_creation_example: `\n\n*Exemplo:* `, + confirm_card_creation_back: `\n*Resposta:* `, + confirm_card_creation_example: `\n*Exemplo:* `, + confirm_many_cards_creation: `Criar esses cartões? Você poderá editá-los no aplicativo após a criação`, confirm_card_creation_front: `Criar cartão?:\n\n*Pergunta:* `, + confirm_many_cards_front: "Pergunta:", + confirm_many_cards_back: "Resposta:", + confirm_many_cards_example: "Exemplo:", + many_cards_created: "Cartões criados 🎉", + no_cards_to_create: "Não há cartões para criar", start_button: "Iniciar bot", }; @@ -107,4 +138,4 @@ export const createTranslator = (lang: Language) => { return new Translator(translations, lang); }; -export type MemoCardTranslator = Translator; +export type MemoCardTranslator = ReturnType;