diff --git a/bot/messages.ts b/bot/messages.ts index 32a7e41d..19b5a692 100644 --- a/bot/messages.ts +++ b/bot/messages.ts @@ -26,6 +26,9 @@ import { IFiat } from '../util/fiatModel'; import { CommunityContext } from './modules/community/communityContext'; import { imageCache } from '../util/imageCache'; import { ImageProcessingError } from '../util/errors'; +import { Community } from '../models'; + +const { I18n } = require('@grammyjs/i18n'); const startMessage = async (ctx: MainContext) => { try { @@ -738,11 +741,25 @@ const publishBuyOrderMessage = async ( const channel = await getOrderChannel(order); if (channel === undefined) throw new Error('channel is undefined'); + + // Get the community language if available + let communityI18n = i18n; + if (order.community_id) { + const community = await Community.findOne({ _id: order.community_id }); + if (community && community.language) { + communityI18n = new I18n({ + defaultLanguageOnMissing: true, + locale: community.language, + directory: 'locales', + }).createContext(community.language); + } + } + // We send the message to the channel const message1 = await bot.telegram.sendMessage(channel, publishMessage, { reply_markup: { inline_keyboard: [ - [{ text: i18n.t('sell_sats'), callback_data: 'takebuy' }], + [{ text: communityI18n.t('sell_sats'), callback_data: 'takebuy' }], ], }, }); @@ -776,11 +793,26 @@ const publishSellOrderMessage = async ( publishMessage += `:${order._id}:`; const channel = await getOrderChannel(order); if (channel === undefined) throw new Error('channel is undefined'); + + // Get the community language if available + let communityI18n = i18n; + + if (order.community_id) { + const community = await Community.findOne({ _id: order.community_id }); + if (community && community.language) { + communityI18n = new I18n({ + defaultLanguageOnMissing: true, + locale: community.language, + directory: 'locales', + }).createContext(community.language); + } + } + // We send the message to the channel const message1 = await ctx.telegram.sendMessage(channel, publishMessage, { reply_markup: { inline_keyboard: [ - [{ text: i18n.t('buy_sats'), callback_data: 'takesell' }], + [{ text: communityI18n.t('buy_sats'), callback_data: 'takesell' }], ], }, }); diff --git a/bot/middleware/stage.ts b/bot/middleware/stage.ts index 9aa7bfd7..424eda3a 100644 --- a/bot/middleware/stage.ts +++ b/bot/middleware/stage.ts @@ -22,6 +22,7 @@ export const stageMiddleware = () => { CommunityModule.Scenes.updateSolversCommunityWizard, CommunityModule.Scenes.updateFeeCommunityWizard, CommunityModule.Scenes.updateDisputeChannelCommunityWizard, + CommunityModule.Scenes.updateLanguageCommunityWizard, CommunityModule.Scenes.addEarningsInvoiceWizard, addInvoicePHIWizard, OrdersModule.Scenes.createOrder, diff --git a/bot/modules/community/commands.ts b/bot/modules/community/commands.ts index cd49a25b..0c62c791 100644 --- a/bot/modules/community/commands.ts +++ b/bot/modules/community/commands.ts @@ -200,6 +200,12 @@ export const updateCommunity = async ( user, community, }); + } else if (field === 'language') { + ctx.scene.enter('UPDATE_LANGUAGE_COMMUNITY_WIZARD_SCENE_ID', { + id, + user, + community, + }); } } catch (error) { logger.error(error); diff --git a/bot/modules/community/index.ts b/bot/modules/community/index.ts index 79b2cee8..9b9eacf9 100644 --- a/bot/modules/community/index.ts +++ b/bot/modules/community/index.ts @@ -54,6 +54,9 @@ export const configure = (bot: Telegraf) => { await commands.updateCommunity(ctx, ctx.match[1], 'disputeChannel', bot); }, ); + bot.action(/^editLanguageBtn_([0-9a-f]{24})$/, userMiddleware, async ctx => { + await commands.updateCommunity(ctx, ctx.match[1], 'language'); + }); bot.command('findcomms', userMiddleware, commands.findCommunity); bot.action( diff --git a/bot/modules/community/messages.ts b/bot/modules/community/messages.ts index 9501b4d0..37be5e97 100644 --- a/bot/modules/community/messages.ts +++ b/bot/modules/community/messages.ts @@ -12,6 +12,7 @@ export const createCommunityWizardStatus = ( try { let { name, group } = state; name = state.name || '__'; + const language = state.language || '__'; let currencies = state.currencies && state.currencies.join(', '); currencies = currencies || '__'; group = state.group || '__'; @@ -27,6 +28,7 @@ export const createCommunityWizardStatus = ( solvers = solvers || '__'; const text = [ i18n.t('name') + `: ${name}`, + i18n.t('language') + `: ${language}`, i18n.t('currency') + `: ${currencies}`, i18n.t('group') + `: ${group}`, i18n.t('channels') + `: ${channels}`, @@ -94,15 +96,21 @@ export const updateCommunityMessage = async (ctx: MainContext) => { callback_data: `editDisputeChannelBtn_${id}`, }, { - text: '💰 ' + ctx.i18n.t('earnings'), - callback_data: `earningsBtn_${id}`, + text: '✏️ ' + ctx.i18n.t('language'), + callback_data: `editLanguageBtn_${id}`, }, ], [ + { + text: '💰 ' + ctx.i18n.t('earnings'), + callback_data: `earningsBtn_${id}`, + }, { text: visibilityText, callback_data: `changeVisibilityBtn_${id}`, }, + ], + [ { text: '☠️ ' + ctx.i18n.t('delete_community'), callback_data: `deleteCommunityAskBtn_${id}`, diff --git a/bot/modules/community/scenes.communityAdmin.ts b/bot/modules/community/scenes.communityAdmin.ts index 2d874c70..5c376f02 100644 --- a/bot/modules/community/scenes.communityAdmin.ts +++ b/bot/modules/community/scenes.communityAdmin.ts @@ -1,5 +1,6 @@ import { Scenes } from 'telegraf'; import { CommunityContext } from './communityContext'; +import { isValidLanguage } from '../../../util/languages'; import * as CommunityEvents from '../events/community'; @@ -37,6 +38,29 @@ const communityAdmin = () => { } }); + scene.command('/setlanguage', async (ctx: CommunityContext) => { + try { + const [, maybeLanguage] = ctx.message!.text.split(' '); + if (!maybeLanguage || maybeLanguage.trim() === '') { + return ctx.reply(ctx.i18n.t('wizard_community_invalid_language')); + } + + const language = maybeLanguage.trim().toLowerCase(); + if (!isValidLanguage(language)) { + return ctx.reply(ctx.i18n.t('wizard_community_invalid_language')); + } + + const { community } = ctx.scene.state as any; + community.language = language; + await community.save(); + await ctx.reply(ctx.i18n.t('community_language_updated', { language })); + CommunityEvents.communityUpdated(community); + } catch (err) { + console.error('setlanguage error:', err); + return ctx.reply(ctx.i18n.t('generic_error')); + } + }); + return scene; }; diff --git a/bot/modules/community/scenes.ts b/bot/modules/community/scenes.ts index da1d835e..b320a13d 100644 --- a/bot/modules/community/scenes.ts +++ b/bot/modules/community/scenes.ts @@ -12,6 +12,7 @@ import { } from './messages'; import { CommunityContext } from './communityContext'; import * as commAdmin from './scenes.communityAdmin'; +import { isValidLanguage } from '../../../util/languages'; const CURRENCIES = parseInt(process.env.COMMUNITY_CURRENCIES || '10'); @@ -25,6 +26,7 @@ export const communityWizard = new Scenes.WizardScene( const { name, + language, currencies, group, channels, @@ -61,6 +63,7 @@ export const communityWizard = new Scenes.WizardScene( } if (undefined === name) return createCommunitySteps.name(ctx); + if (undefined === language) return createCommunitySteps.language(ctx); if (undefined === currencies) return createCommunitySteps.currencies(ctx); if (undefined === group) return createCommunitySteps.group(ctx); if (undefined === channels) return createCommunitySteps.channels(ctx); @@ -71,6 +74,7 @@ export const communityWizard = new Scenes.WizardScene( const community = new Community({ name, + language, currencies, group, order_channels: channels, @@ -150,6 +154,38 @@ const createCommunitySteps = { return ctx.wizard.next(); }, + async language(ctx: CommunityContext) { + const prompt = await createCommunityPrompts.language(ctx); + + ctx.wizard.state.handler = async (ctx: CommunityContext) => { + const text = ctx?.message?.text; + if (!text) { + await ctx.deleteMessage(); + return ctx.telegram.deleteMessage(prompt.chat.id, prompt.message_id); + } + + ctx.wizard.state.error = null; + const lang = text.trim().toLowerCase(); + + if (!isValidLanguage(lang)) { + ctx.telegram.deleteMessage(ctx.chat!.id, ctx.message!.message_id); + ctx.wizard.state.error = ctx.i18n.t( + 'wizard_community_invalid_language', + ); + return await ctx.wizard.state.updateUI(); + } + + ctx.wizard.state.language = lang; + await ctx.wizard.state.updateUI(); + await ctx.telegram.deleteMessage( + ctx.message!.chat.id, + ctx.message!.message_id, + ); + return ctx.telegram.deleteMessage(prompt.chat.id, prompt.message_id); + }; + + return ctx.wizard.next(); + }, async currencies(ctx: CommunityContext) { const prompt = await createCommunityPrompts.currencies(ctx); @@ -427,6 +463,9 @@ const createCommunityPrompts = { async name(ctx: CommunityContext) { return ctx.reply(ctx.i18n.t('wizard_community_enter_name')); }, + async language(ctx: CommunityContext) { + return ctx.reply(ctx.i18n.t('wizard_community_enter_language')); + }, async currencies(ctx: CommunityContext) { return ctx.reply(ctx.i18n.t('wizard_community_enter_currency')); }, @@ -837,6 +876,46 @@ export const updateDisputeChannelCommunityWizard = new Scenes.WizardScene( }, ); +export const updateLanguageCommunityWizard = new Scenes.WizardScene( + 'UPDATE_LANGUAGE_COMMUNITY_WIZARD_SCENE_ID', + async (ctx: CommunityContext) => { + try { + const { community } = ctx.wizard.state; + let message = + ctx.i18n.t('language') + ': ' + (community.language || 'en') + '\n\n'; + message += ctx.i18n.t('wizard_community_enter_language') + '\n\n'; + message += ctx.i18n.t('wizard_to_exit'); + await ctx.reply(message); + + return ctx.wizard.next(); + } catch (error) { + logger.error(error); + ctx.scene.leave(); + } + }, + async (ctx: CommunityContext) => { + try { + if (ctx.message === undefined) return ctx.scene.leave(); + + const lang = ctx.message.text.trim().toLowerCase(); + if (!isValidLanguage(lang)) { + ctx.deleteMessage(); + return await ctx.reply(ctx.i18n.t('wizard_community_invalid_language')); + } + + const { community } = ctx.wizard.state; + community.language = lang; + await community.save(); + await ctx.reply(ctx.i18n.t('operation_successful')); + + return ctx.scene.leave(); + } catch (error) { + logger.error(error); + ctx.scene.leave(); + } + }, +); + export const addEarningsInvoiceWizard = new Scenes.WizardScene( 'ADD_EARNINGS_INVOICE_WIZARD_SCENE_ID', async (ctx: CommunityContext) => { diff --git a/bot/ordersActions.ts b/bot/ordersActions.ts index 8d632633..fa49bc3c 100644 --- a/bot/ordersActions.ts +++ b/bot/ordersActions.ts @@ -15,9 +15,11 @@ import { UserDocument } from '../models/user'; import { HasTelegram, MainContext } from './start'; import { IOrder } from '../models/order'; import { IFiat } from '../util/fiatModel'; + import * as OrderEvents from './modules/events/orders'; const { ObjectId } = require('mongoose').Types; +const { I18n } = require('@grammyjs/i18n'); interface CreateOrderArguments { type: string; @@ -73,10 +75,23 @@ const createOrder = async ( try { amount = Math.floor(amount); let isPublic = true; + + // Use community language if community_id is provided + let descriptionI18n = i18n; + if (community_id) { const community = await Community.findById(community_id); if (community == null) throw new Error('community is null'); isPublic = community.public; + + // Get community language for description + if (community.language) { + descriptionI18n = new I18n({ + defaultLanguageOnMissing: true, + locale: community.language, + directory: 'locales', + }).createContext(community.language); + } } const fee = await getFee(amount, community_id || ''); if (process.env.MAX_FEE === undefined) @@ -129,7 +144,7 @@ const createOrder = async ( tg_order_message: tgOrderMessage, price_from_api: priceFromAPI, price_margin: priceMargin || 0, - description: buildDescription(i18n, { + description: buildDescription(descriptionI18n, { user, type, amount, diff --git a/locales/de.yaml b/locales/de.yaml index 1f647803..bc69bedf 100644 --- a/locales/de.yaml +++ b/locales/de.yaml @@ -570,6 +570,8 @@ community_admin: | ${community.fee} Earnings: ${community.earnings} + Language: + ${community.language || 'de'} npub: ${community.nostr_public_key || ''} @@ -580,7 +582,12 @@ community_admin_help: | # commands /setnpub <npub> - Configure Nostr community's public key. + /setlanguage <lang> - Konfiguriere die Sprache der Community für veröffentlichte Nachrichten. community_npub_updated: You added the community's pubkey ${npub} successfully! +community_language_updated: Du hast die Sprache der Community erfolgreich auf ${language} aktualisiert! +wizard_community_enter_language: 'Gib den Sprachcode für deine Community ein (en, es, fr, de, it, pt, ru, uk, ko, fa)' +wizard_community_invalid_language: 'Ungültiger Sprachcode. Bitte gib einen der folgenden ein - en, es, fr, de, it, pt, ru, uk, ko, fa' +language: "Sprache" # END modules/community # START modules/orders diff --git a/locales/en.yaml b/locales/en.yaml index 3d886029..60bb25c9 100644 --- a/locales/en.yaml +++ b/locales/en.yaml @@ -559,6 +559,8 @@ community_admin: | ${community.fee} Earnings: ${community.earnings} + Language: + ${community.language || 'en'} npub: ${community.nostr_public_key || ''} @@ -569,7 +571,12 @@ community_admin_help: | # commands /setnpub <npub> - Configure Nostr community's public key. + /setlanguage <lang> - Configure community's language for published messages. community_npub_updated: You added the community's pubkey ${npub} successfully! +community_language_updated: You updated the community's language to ${language} successfully! +wizard_community_enter_language: 'Enter the language code for your community (en, es, fr, de, it, pt, ru, uk, ko, fa)' +wizard_community_invalid_language: 'Invalid language code. Please enter one of the following - en, es, fr, de, it, pt, ru, uk, ko, fa' +language: Language # END modules/community # START modules/nostr diff --git a/locales/es.yaml b/locales/es.yaml index 02715af1..ed44d26e 100644 --- a/locales/es.yaml +++ b/locales/es.yaml @@ -554,6 +554,8 @@ community_admin: | ${community.fee} Ganancias: ${community.earnings} + Idioma: + ${community.language || 'es'} npub: ${community.nostr_public_key || ''} @@ -564,7 +566,12 @@ community_admin_help: | # comandos /setnpub <npub> - Configura la llave pública de Nostr de la comunidad. -community_npub_updated: Has configurado la pubkey ${npub} de la comunidad exitosamente! + /setlanguage <lang> - Configura el idioma de la comunidad para los mensajes publicados. +community_npub_updated: ¡Has configurado la pubkey ${npub} de la comunidad exitosamente! +community_language_updated: ¡Has configurado el idioma ${language} de la comunidad exitosamente! +wizard_community_enter_language: 'Ingresa el idioma de la comunidad, ej: es, en, pt, fr, de, it, etc.' +wizard_community_invalid_language: 'El idioma debe ser uno de los siguientes: es, en, pt, fr, de, it, etc.' +language: "Idioma" # END modules/community # START modules/nostr diff --git a/locales/fa.yaml b/locales/fa.yaml index 31530779..fce42fa6 100644 --- a/locales/fa.yaml +++ b/locales/fa.yaml @@ -553,6 +553,8 @@ community_admin: | ${community.fee} Earnings: ${community.earnings} + Language: + ${community.language || 'fa'} npub: ${community.nostr_public_key || ''} @@ -563,7 +565,12 @@ community_admin_help: | # commands /setnpub <npub> - کلید عمومی جامعه را پیکربندی کنید. رویدادهای ناستر با این کلید عمومی برچسب‌گذاری می‌شوند. + /setlanguage <lang> - زبان کامیونیتی را برای پیام‌های منتشرشده پیکربندی کنید. +community_language_updated: شما زبان کامیونیتی را با موفقیت به ${language} به‌روزرسانی کردید! +wizard_community_enter_language: 'کد زبان کامیونیتی خود را وارد کنید (en, es, fr, de, it, pt, ru, uk, ko, fa)' +wizard_community_invalid_language: 'کد زبان نامعتبر است. لطفاً یکی از موارد زیر را وارد کنید - en, es, fr, de, it, pt, ru, uk, ko, fa' community_npub_updated: شما کلیدعمومی کامیونیتی ${npub} را با موفقیت اضافه کردید! +language: "زبان" # END modules/community # START modules/nostr diff --git a/locales/fr.yaml b/locales/fr.yaml index 15b4fe88..07074e51 100644 --- a/locales/fr.yaml +++ b/locales/fr.yaml @@ -552,6 +552,8 @@ community_admin: | ${community.fee} Earnings: ${community.earnings} + Language: + ${community.language || 'fr'} npub: ${community.nostr_public_key || ''} @@ -562,7 +564,12 @@ community_admin_help: | # commands /setnpub <npub> - Configurer la clé publique de la communauté. + /setlanguage <lang> - Configurer la langue de la communauté pour les messages publiés. +community_language_updated: Vous avez configuré la langue de la communauté en ${language} avec succès ! +wizard_community_enter_language: 'Entrez le code de la langue de votre communauté (en, es, fr, de, it, pt, ru, uk, ko, fa)' +wizard_community_invalid_language: "Code de langue invalide. Veuillez entrer l'un des suivants - en, es, fr, de, it, pt, ru, uk, ko, fa" community_npub_updated: Vous avez ajouté la clé publique de la communauté ${npub} avec succès ! +language: "Langue" # END modules/community # START modules/nostr diff --git a/locales/it.yaml b/locales/it.yaml index 60043fe4..fa66ebad 100644 --- a/locales/it.yaml +++ b/locales/it.yaml @@ -567,6 +567,8 @@ community_admin: | ${community.fee} Earnings: ${community.earnings} + Language: + ${community.language || 'it'} npub: ${community.nostr_public_key || ''} @@ -577,7 +579,12 @@ community_admin_help: | # commands /setnpub <npub> - Configure community's public key. + /setlanguage <lang> - Configura la lingua della community per i messaggi pubblicati. +community_language_updated: Hai aggiornato con successo la lingua della community a ${language}! +wizard_community_enter_language: 'Inserisci il codice lingua per la tua community (en, es, fr, de, it, pt, ru, uk, ko, fa)' +wizard_community_invalid_language: 'Codice lingua non valido. Inserisci uno dei seguenti - en, es, fr, de, it, pt, ru, uk, ko, fa' community_npub_updated: You added the community's pubkey ${npub} successfully! +language: "Lingua" # END modules/community # START modules/orders diff --git a/locales/ko.yaml b/locales/ko.yaml index ce324ad4..6dc3b9d3 100644 --- a/locales/ko.yaml +++ b/locales/ko.yaml @@ -550,6 +550,8 @@ community_admin: | ${community.fee} 수익: ${community.earnings} + Language: + ${community.language || 'ko'} npub: ${community.nostr_public_key || ''} @@ -560,7 +562,12 @@ community_admin_help: | # 명령어 /setnpub <npub> - 커뮤니티의 Nostr npub을 등록합니다. Nostr 이벤트들은 이 npub으로 등록됩니다. + /setlanguage <lang> - 커뮤니티의 언어를 설정합니다. +community_language_updated: 성공적으로 커뮤니티의 언어를 ${language}로 설정하였습니다! +wizard_community_enter_language: '커뮤니티의 언어를 입력하세요. (en, es, fr, de, it, pt, ru, uk, ko, fa)' +wizard_community_invalid_language: '유효하지 않은 언어입니다. 다음 중 하나를 입력하세요: en, es, fr, de, it, pt, ru, uk, ko, fa' community_npub_updated: 성공적으로 커뮤니티의 공개키 ${npub}을 추가하였습니다! +language: "언어" # END modules/community # START modules/nostr diff --git a/locales/pt.yaml b/locales/pt.yaml index bd3a5fa7..a2bc8592 100644 --- a/locales/pt.yaml +++ b/locales/pt.yaml @@ -569,6 +569,8 @@ community_admin: | ${community.fee} Earnings: ${community.earnings} + Language: + ${community.language || 'pt'} npub: ${community.nostr_public_key || ''} @@ -579,7 +581,12 @@ community_admin_help: | # commands /setnpub <npub> - Configure community's public key. + /setlanguage <lang> - Configure o idioma da comunidade para mensagens publicadas. +community_language_updated: Você atualizou o idioma da comunidade para ${language} com sucesso! +wizard_community_enter_language: 'Insira o código de idioma da sua comunidade (en, es, fr, de, it, pt, ru, uk, ko, fa)' +wizard_community_invalid_language: 'Código de idioma inválido. Insira um dos seguintes - en, es, fr, de, it, pt, ru, uk, ko, fa' community_npub_updated: You added the community's pubkey ${npub} successfully! +language: "Idioma" # END modules/community # START modules/orders diff --git a/locales/ru.yaml b/locales/ru.yaml index dea0cd9a..79b1a6ae 100644 --- a/locales/ru.yaml +++ b/locales/ru.yaml @@ -570,6 +570,8 @@ community_admin: | ${community.fee} Earnings: ${community.earnings} + Language: + ${community.language || 'ru'} npub: ${community.nostr_public_key || ''} @@ -580,7 +582,12 @@ community_admin_help: | # commands /setnpub <npub> - Configure community's Nostr public key. + /setlanguage <lang> - Настройте язык сообщества для публикуемых сообщений. +community_language_updated: Вы успешно обновили язык сообщества на ${language}! +wizard_community_enter_language: 'Введите код языка для вашего сообщества (en, es, fr, de, it, pt, ru, uk, ko, fa)' +wizard_community_invalid_language: 'Недопустимый код языка. Пожалуйста, введите один из следующих - en, es, fr, de, it, pt, ru, uk, ko, fa' community_npub_updated: You added the community's pubkey ${npub} successfully! +language: "Язык" # END modules/community # START modules/orders diff --git a/locales/uk.yaml b/locales/uk.yaml index 40e76f35..8202ce68 100644 --- a/locales/uk.yaml +++ b/locales/uk.yaml @@ -566,6 +566,8 @@ community_admin: | ${community.fee} Earnings: ${community.earnings} + Language: + ${community.language || 'uk'} npub: ${community.nostr_public_key || ''} @@ -576,7 +578,12 @@ community_admin_help: | # commands /setnpub <npub> - Configure community's Nostr public key. + /setlanguage <lang> - Налаштуйте мову спільноти для опублікованих повідомлень. +community_language_updated: Ви успішно оновили мову спільноти на ${language}! +wizard_community_enter_language: 'Введіть код мови для вашої спільноти (en, es, fr, de, it, pt, ru, uk, ko, fa)' +wizard_community_invalid_language: 'Недійсний код мови. Будь ласка, введіть один із таких - en, es, fr, de, it, pt, ru, uk, ko, fa' community_npub_updated: You added the community's pubkey ${npub} successfully! +language: "Мова" # END modules/community # START modules/orders diff --git a/models/community.ts b/models/community.ts index c23b75b6..dcd134c5 100644 --- a/models/community.ts +++ b/models/community.ts @@ -1,4 +1,5 @@ import mongoose, { Document, Schema, Types } from 'mongoose'; +import { isValidLanguage, SUPPORTED_LANGUAGES } from '../util/languages'; const CURRENCIES: number = parseInt(process.env.COMMUNITY_CURRENCIES || '10'); @@ -49,6 +50,7 @@ export interface ICommunity extends Document { created_at: Date; nostr_public_key: string; warning_messages_count: number; + language: string; } const CommunitySchema = new Schema({ @@ -82,6 +84,14 @@ const CommunitySchema = new Schema({ created_at: { type: Date, default: Date.now }, nostr_public_key: { type: String }, warning_messages_count: { type: Number, default: 0 }, + language: { + type: String, + trim: true, + lowercase: true, + default: 'en', + enum: SUPPORTED_LANGUAGES, + validate: [isValidLanguage, 'Language code {VALUE} is not supported'], + }, }); export default mongoose.model('Community', CommunitySchema); diff --git a/util/languages.ts b/util/languages.ts new file mode 100644 index 00000000..267d8660 --- /dev/null +++ b/util/languages.ts @@ -0,0 +1,17 @@ +export const SUPPORTED_LANGUAGES = [ + 'en', + 'es', + 'fr', + 'de', + 'it', + 'pt', + 'ru', + 'uk', + 'ko', + 'fa', +] as const; +export type SupportedLanguage = (typeof SUPPORTED_LANGUAGES)[number]; + +export const isValidLanguage = (lang: string): lang is SupportedLanguage => { + return SUPPORTED_LANGUAGES.includes(lang as SupportedLanguage); +};