diff --git a/README.md b/README.md index af117ac4a..d05cb55db 100644 --- a/README.md +++ b/README.md @@ -27,9 +27,9 @@ - Notable differences: - Improved UI/UX (especially on mobile) - Improved notifications - - Fediverse account migration - Improved instance security - Improved accessibility + - Improved threads - Recommended Instances timeline - OCR image captioning - New and improved Groups diff --git a/locales/ca-ES.yml b/locales/ca-ES.yml index 24e4b6d7d..b226d641e 100644 --- a/locales/ca-ES.yml +++ b/locales/ca-ES.yml @@ -675,3 +675,48 @@ useGlobalSetting: Fes servir els ajustos globals useGlobalSettingDesc: Si s'activa, es faran servir els ajustos de notificacions del teu compte. Si es desactiva , es poden fer configuracions individuals. other: Altres +menu: Menú +addItem: Afegeix un element +divider: Divisor +relays: Relés +addRelay: Afegeix un Relé +inboxUrl: Adreça de la safata d'entrada +addedRelays: Relés afegits +serviceworkerInfo: Ha de estar activat per les notificacions push. +poll: Enquesta +deletedNote: Article eliminat +disablePlayer: Tancar el reproductor de vídeo +fileIdOrUrl: ID o adreça URL del fitxer +behavior: Comportament +regenerateLoginTokenDescription: Regenera el token que es fa servir de manera interna + durant l'inici de sessió. Normalment això no és necessari. Si es torna a genera + el token, es tancarà la sessió a tots els dispositius. +setMultipleBySeparatingWithSpace: Separa diferents entrades amb espais. +reportAbuseOf: Informa sobre {name} +sample: Exemple +abuseReports: Informes +reportAbuse: Informe +reporter: Informador +reporterOrigin: Origen d'el informador +forwardReport: Envia l'informe a una instancia remota +abuseReported: El teu informe ha sigut enviat. Moltes gràcies. +reporteeOrigin: Origen de l'informe +send: Enviar +abuseMarkAsResolved: Marcar l'informe com a resolt +visibility: Visibilitat +useCw: Amaga el contingut +enablePlayer: Obre el reproductor de vídeo +yourAccountSuspendedDescription: Aquest compte ha sigut suspesa per no seguir els + termes de servei del servidor o quelcom similar. Contacte amb l'administrador si + vols conèixer la raó amb més detall. Si us plau no facis un compte nou. +invisibleNote: Article ocult +enableInfiniteScroll: Carregar més de forma automàtica +fillAbuseReportDescription: Si us plau omple els detalls sobre aquest informe. Si + es sobre un article en concret, si us plau inclou l'adreça URL. +forwardReportIsAnonymous: Com a informador a l'instància remota no es mostrarà el + teu compte, si no un compte anònim. +openInNewTab: Obrir en una pestanya nova +openInSideView: Obrir a la vista lateral +defaultNavigationBehaviour: Navegació per defecte +editTheseSettingsMayBreakAccount: Si edites aquestes configuracions pots fer mal bé + el teu compte. diff --git a/locales/en-US.yml b/locales/en-US.yml index 2feb2cd94..f9d4d23f0 100644 --- a/locales/en-US.yml +++ b/locales/en-US.yml @@ -1042,7 +1042,7 @@ moveFromLabel: "Account you're moving from:" moveFromDescription: "This will set an alias of your old account so that you can move\ \ from that account to this current one. Do this BEFORE moving from your older account.\ \ Please enter the tag of the account formatted like @person@instance.com" -migrationConfirm: "Are you absolutely sure you want to migrate your acccount to {account}?\ +migrationConfirm: "Are you absolutely sure you want to migrate your account to {account}?\ \ Once you do this, you won't be able to reverse it, and you won't be able to use\ \ your account normally again.\nAlso, please ensure that you've set this current\ \ account as the account you're moving from." diff --git a/locales/fi.yml b/locales/fi.yml index c9e5e06e0..fd6c160e6 100644 --- a/locales/fi.yml +++ b/locales/fi.yml @@ -3,7 +3,7 @@ fetchingAsApObject: Hae Fedeversestä gotIt: Selvä! cancel: Peruuta enterUsername: Anna käyttäjänimi -renotedBy: Buustannut {käyttäjä} +renotedBy: Buustannut {user} noNotes: Ei lähetyksiä noNotifications: Ei ilmoituksia instance: Instanssi @@ -41,3 +41,183 @@ favorite: Lisää kirjanmerkkeihin copyContent: Kopioi sisältö deleteAndEdit: Poista ja muokkaa copyLink: Kopioi linkki +makeFollowManuallyApprove: Seuraajapyyntö vaatii hyväksymistä +follow: Seuraa +pinned: Kiinnitä profiiliin +followRequestPending: Seuraajapyyntö odottaa +you: Sinä +unrenote: Peruuta buustaus +reaction: Reaktiot +reactionSettingDescription2: Vedä uudelleenjärjestelläksesi, napsauta poistaaksesi, + paina "+" lisätäksesi. +attachCancel: Poista liite +enterFileName: Anna tiedostonimi +mute: Hiljennä +unmute: Poista hiljennys +headlineMisskey: Avoimen lähdekoodin, hajautettu sosiaalisen median alusta, joka on + ikuisesti ilmainen! 🚀 +monthAndDay: '{day}/{month}' +deleteAndEditConfirm: Oletko varma, että haluat poistaa tämän lähetyksen ja muokata + sitä? Menetät kaikki reaktiot, buustaukset ja vastaukset lähetyksestäsi. +addToList: Lisää listaan +sendMessage: Lähetä viesti +reply: Vastaa +loadMore: Lataa enemmän +showMore: Näytä enemmän +receiveFollowRequest: Seuraajapyyntö vastaanotettu +followRequestAccepted: Seuraajapyyntö hyväksytty +mentions: Maininnat +importAndExport: Tuo/Vie Tietosisältö +import: Tuo +export: Vie +files: Tiedostot +download: Lataa +unfollowConfirm: Oletko varma, ettet halua seurata enää käyttäjää {name}? +noLists: Sinulla ei ole listoja +note: Lähetys +notes: Lähetykset +following: Seuraa +createList: Luo lista +manageLists: Hallitse listoja +error: Virhe +somethingHappened: On tapahtunut virhe +retry: Yritä uudelleen +pageLoadError: Virhe ladattaessa sivua. +serverIsDead: Tämä palvelin ei vastaa. Yritä hetken kuluttua uudelleen. +youShouldUpgradeClient: Nähdäksesi tämän sivun, virkistä päivittääksesi asiakasohjelmasi. +privacy: Tietosuoja +defaultNoteVisibility: Oletusnäkyvyys +followRequest: Seuraajapyyntö +followRequests: Seuraajapyynnöt +unfollow: Poista seuraaminen +enterEmoji: Syötä emoji +renote: Buustaa +renoted: Buustattu. +cantRenote: Tätä lähetystä ei voi buustata. +cantReRenote: Buustausta ei voi buustata. +quote: Lainaus +pinnedNote: Lukittu lähetys +clickToShow: Napsauta nähdäksesi +sensitive: Herkkää sisältöä (NSFW) +add: Lisää +enableEmojiReactions: Ota käyttöön emoji-reaktiot +showEmojisInReactionNotifications: Näytä emojit reaktioilmoituksissa +reactionSetting: Reaktiot näytettäväksi reaktiovalitsimessa +rememberNoteVisibility: Muista lähetyksen näkyvyysasetukset +markAsSensitive: Merkitse herkäksi sisällöksi (NSFW) +unmarkAsSensitive: Poista merkintä herkkää sisältöä (NSFW) +renoteMute: Hiljennä buustit +renoteUnmute: Poista buustien hiljennys +block: Estä +unblock: Poista esto +unsuspend: Poista keskeytys +suspend: Keskeytys +blockConfirm: Oletko varma, että haluat estää tämän tilin? +unblockConfirm: Oletko varma, että haluat poistaa tämän tilin eston? +selectAntenna: Valitse antenni +selectWidget: Valitse vimpain +editWidgets: Muokkaa vimpaimia +editWidgetsExit: Valmis +emoji: Emoji +emojis: Emojit +emojiName: Emojin nimi +emojiUrl: Emojin URL-linkki +cacheRemoteFiles: Taltioi etätiedostot välimuistiin +flagAsBot: Merkitse tili botiksi +flagAsBotDescription: Ota tämä vaihtoehto käyttöön, jos tätä tiliä ohjaa ohjelma. + Jos se on käytössä, se toimii lippuna muille kehittäjille, jotta estetään loputtomat + vuorovaikutusketjut muiden bottien kanssa ja säädetään Calckeyn sisäiset järjestelmät + käsittelemään tätä tiliä botina. +flagAsCat: Oletko kissa? 🐱 +flagAsCatDescription: Saat kissan korvat ja puhut kuin kissa! +flagSpeakAsCat: Puhu kuin kissa +flagShowTimelineReplies: Näytä vastaukset aikajanalla +addAccount: Lisää tili +loginFailed: Kirjautuminen epäonnistui +showOnRemote: Katsele etäinstanssilla +general: Yleistä +accountMoved: 'Käyttäjä on muuttanut uuteen tiliin:' +wallpaper: Taustakuva +setWallpaper: Aseta taustakuva +searchWith: 'Etsi: {q}' +youHaveNoLists: Sinulla ei ole listoja +followConfirm: Oletko varma, että haluat seurata käyttäjää {name}? +host: Isäntä +selectUser: Valitse käyttäjä +annotation: Kommentit +registeredAt: Rekisteröity +latestRequestReceivedAt: Viimeisin pyyntö vastaanotettu +latestRequestSentAt: Viimeisin pyyntö lähetetty +storageUsage: Tallennustilan käyttö +charts: Kaaviot +stopActivityDelivery: Lopeta toimintojen lähettäminen +blockThisInstance: Estä tämä instanssi +operations: Toiminnot +metadata: Metatieto +monitor: Seuranta +jobQueue: Työjono +cpuAndMemory: Prosessori ja muisti +network: Verkko +disk: Levy +clearCachedFiles: Tyhjennä välimuisti +clearCachedFilesConfirm: Oletko varma, että haluat tyhjentää kaikki välimuistiin tallennetut + etätiedostot? +blockedInstances: Estetyt instanssit +hiddenTags: Piilotetut asiatunnisteet +mention: Maininta +copyUsername: Kopioi käyttäjänimi +searchUser: Etsi käyttäjää +showLess: Sulje +youGotNewFollower: seurasi sinua +directNotes: Yksityisviestit +driveFileDeleteConfirm: Oletko varma, että haluat poistaa tiedoston " {name}"? Lähetykset, + jotka sisältyvät tiedostoon, poistuvat myös. +importRequested: Olet pyytänyt viemistä. Tämä voi viedä hetken. +exportRequested: Olet pyytänyt tuomista. Tämä voi viedä hetken. Se lisätään asemaan + kun tuonti valmistuu. +lists: Listat +followers: Seuraajat +followsYou: Seuraa sinua +pageLoadErrorDescription: Tämä yleensä johtuu verkkovirheistä tai selaimen välimuistista. + Kokeile tyhjentämällä välimuisti ja yritä sitten hetken kuluttua uudelleen. +enterListName: Anna listalle nimi +withNFiles: '{n} tiedosto(t)' +instanceInfo: Instanssin tiedot +clearQueue: Tyhjennä jono +suspendConfirm: Oletko varma, että haluat keskeyttää tämän tilin? +unsuspendConfirm: Oletko varma, että haluat poistaa tämän tilin keskeytyksen? +selectList: Valitse lista +customEmojis: Kustomoitu Emoji +addEmoji: Lisää +settingGuide: Suositellut asetukset +cacheRemoteFilesDescription: Kun tämä asetus ei ole käytössä, etätiedostot on ladattu + suoraan etäinstanssilta. Asetuksen poistaminen käytöstä vähentää tallennustilan + käyttöä, mutta lisää verkkoliikennettä kun pienoiskuvat eivät muodostu. +flagSpeakAsCatDescription: Lähetyksesi nyanifioidaan, kun olet kissatilassa +flagShowTimelineRepliesDescription: Näyttää käyttäjien vastaukset muiden käyttäjien + lähetyksiin aikajanalla, jos se on päällä. +autoAcceptFollowed: Automaattisesti hyväksy seuraamispyynnöt käyttäjiltä, joita seuraat +perHour: Tunnissa +removeWallpaper: Poista taustakuva +recipient: Vastaanottaja(t) +federation: Federaatio +software: Ohjelmisto +proxyAccount: Proxy-tili +proxyAccountDescription: Välitystili (Proxy-tili) on tili, joka toimii käyttäjien + etäseuraajana tietyin edellytyksin. Kun käyttäjä esimerkiksi lisää etäkäyttäjän + luetteloon, etäkäyttäjän toimintaa ei toimiteta instanssiin, jos yksikään paikallinen + käyttäjä ei seuraa kyseistä käyttäjää, joten välitystili seuraa sen sijaan. +latestStatus: Viimeisin tila +selectInstance: Valitse instanssi +instances: Instanssit +perDay: Päivässä +version: Versio +statistics: Tilastot +clearQueueConfirmTitle: Oletko varma, että haluat tyhjentää jonon? +introMisskey: Tervetuloa! Calckey on avoimen lähdekoodin, hajautettu sosiaalisen median + alusta, joka on ikuisesti ilmainen! 🚀 +clearQueueConfirmText: Mitkään välittämättömät lähetykset, jotka ovat jonossa, eivät + federoidu. Yleensä tätä toimintoa ei tarvita. +blockedInstancesDescription: Lista instanssien isäntänimistä, jotka haluat estää. + Listatut instanssit eivät kykene kommunikoimaan enää tämän instanssin kanssa. +_lang_: Suomi diff --git a/package.json b/package.json index a204a05fe..78e39e69f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "calckey", - "version": "13.2.0-dev38", + "version": "13.2.0-dev41", "codename": "aqua", "repository": { "type": "git", diff --git a/packages/backend/assets/favicon.ico b/packages/backend/assets/favicon.ico index fd7aadf2e..8d46b0c1d 100644 --- a/packages/backend/assets/favicon.ico +++ b/packages/backend/assets/favicon.ico @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ce4ba88c40e8d79d697cead7ccad4325846c03995f429194e19a5aa1383b7a82 -size 3973 +oid sha256:c414a146ef32ee9017444a977d5b6bb40079be9cdfeaab9a8a58f836fb6eea62 +size 4286 diff --git a/packages/backend/assets/favicon.png b/packages/backend/assets/favicon.png index b90943252..44d777ceb 100644 --- a/packages/backend/assets/favicon.png +++ b/packages/backend/assets/favicon.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c259dc343a2824ee408c5e2daafa56abd0b31d29fd1f4c59be7d9d1fe0c5e379 -size 3951 +oid sha256:25f2b237d58b1094ff047ae1d8653fafeb1ae79b5997054f6997c4c252ab1a4e +size 6122 diff --git a/packages/backend/assets/favicon.svg b/packages/backend/assets/favicon.svg index 7f55f6312..4e00347fb 100644 --- a/packages/backend/assets/favicon.svg +++ b/packages/backend/assets/favicon.svg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4f17cc091606efe4c5e6fc3dbf04b018bc169705f352d52c43dc771d5a716a1d -size 4285 +oid sha256:3d6f88a7b660f9960a5ed9ac4473ec447b46a0b79d02064639c05729519af39d +size 2890 diff --git a/packages/backend/assets/icons/192.png b/packages/backend/assets/icons/192.png index 51434dd78..48a863e34 100644 --- a/packages/backend/assets/icons/192.png +++ b/packages/backend/assets/icons/192.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:712381afff5aaf9f5ed479d8862a67ca5581307c5b807d7cfa3edf813cf214ad -size 7000 +oid sha256:ef1b3ac7867fa31073dd30b8bb90ef942d74446fadec5e663ae662bd3b74f8bd +size 7483 diff --git a/packages/backend/assets/icons/512.png b/packages/backend/assets/icons/512.png index 8c45a6311..e5ba760ad 100644 --- a/packages/backend/assets/icons/512.png +++ b/packages/backend/assets/icons/512.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:27b9944477bdba4219e6f3af9af3393d947fbcc52f88b3d9ecf9df06547cd970 -size 7099 +oid sha256:23616706bb3475f88e355c7489f48306b37d0f6aa3de5cf5559ce357a5b728ba +size 21631 diff --git a/packages/backend/assets/inverse wordmark.png b/packages/backend/assets/inverse wordmark.png new file mode 100644 index 000000000..e5ba760ad --- /dev/null +++ b/packages/backend/assets/inverse wordmark.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:23616706bb3475f88e355c7489f48306b37d0f6aa3de5cf5559ce357a5b728ba +size 21631 diff --git a/packages/backend/assets/inverse wordmark.svg b/packages/backend/assets/inverse wordmark.svg index fe9a77be9..33d426136 100644 --- a/packages/backend/assets/inverse wordmark.svg +++ b/packages/backend/assets/inverse wordmark.svg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:be36c9edc904f05d7f4a96f2092154b14cd7696fc2b9a317e77e56d85f1f06a0 -size 4395 +oid sha256:b034df14985fe2e6a3f2b37d80ed5144a2c75be2cf8393b236a71ef55e6432ba +size 2163 diff --git a/packages/backend/assets/splash.png b/packages/backend/assets/splash.png index 0547a8f19..1e396a741 100644 --- a/packages/backend/assets/splash.png +++ b/packages/backend/assets/splash.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a751c980d885ce137f65ae4baaacd89f46b8206774db3b90fb32ac7c06a3a8ed -size 9326 +oid sha256:67df7f31c099111ad56e98d75a71340c4274d27e0f38c979e941c1d5d073e3e8 +size 21007 diff --git a/packages/backend/migration/1682777547198-LibreTranslate.js b/packages/backend/migration/1682777547198-LibreTranslate.js new file mode 100644 index 000000000..dbaf483e6 --- /dev/null +++ b/packages/backend/migration/1682777547198-LibreTranslate.js @@ -0,0 +1,23 @@ +export class LibreTranslate1682777547198 { + name = "LibreTranslate1682777547198"; + + async up(queryRunner) { + await queryRunner.query(` + ALTER TABLE "meta" + ADD "libreTranslateApiUrl" character varying(512) + `); + await queryRunner.query(` + ALTER TABLE "meta" + ADD "libreTranslateApiKey" character varying(128) + `); + } + + async down(queryRunner) { + await queryRunner.query(` + ALTER TABLE "meta" DROP COLUMN "libreTranslateApiKey" + `); + await queryRunner.query(` + ALTER TABLE "meta" DROP COLUMN "libreTranslateApiUrl" + `); + } +} diff --git a/packages/backend/package.json b/packages/backend/package.json index 7b92b8311..ce0b2c2e1 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -26,7 +26,7 @@ "@bull-board/api": "^4.6.4", "@bull-board/koa": "^4.6.4", "@bull-board/ui": "^4.6.4", - "@calckey/megalodon": "5.1.24", + "@calckey/megalodon": "5.2.0", "@discordapp/twemoji": "14.0.2", "@elastic/elasticsearch": "7.17.0", "@koa/cors": "3.4.3", diff --git a/packages/backend/src/config/types.ts b/packages/backend/src/config/types.ts index 4f367debe..0cd8c02ad 100644 --- a/packages/backend/src/config/types.ts +++ b/packages/backend/src/config/types.ts @@ -89,6 +89,11 @@ export type Source = { authKey?: string; isPro?: boolean; }; + libreTranslate: { + managed?: boolean; + apiUrl?: string; + apiKey?: string; + }; email: { managed?: boolean; address?: string; diff --git a/packages/backend/src/models/entities/meta.ts b/packages/backend/src/models/entities/meta.ts index 26a7c9c19..2f77796c4 100644 --- a/packages/backend/src/models/entities/meta.ts +++ b/packages/backend/src/models/entities/meta.ts @@ -386,6 +386,18 @@ export class Meta { }) public deeplIsPro: boolean; + @Column('varchar', { + length: 512, + nullable: true, + }) + public libreTranslateApiUrl: string | null; + + @Column('varchar', { + length: 128, + nullable: true, + }) + public libreTranslateApiKey: string | null; + @Column('varchar', { length: 512, nullable: true, diff --git a/packages/backend/src/server/api/endpoints/admin/accounts/hosted.ts b/packages/backend/src/server/api/endpoints/admin/accounts/hosted.ts index 15ad1f9a1..a7b6e95c2 100644 --- a/packages/backend/src/server/api/endpoints/admin/accounts/hosted.ts +++ b/packages/backend/src/server/api/endpoints/admin/accounts/hosted.ts @@ -30,6 +30,17 @@ export default define(meta, paramDef, async (ps, me) => { set.deeplIsPro = config.deepl.isPro; } } + if ( + config.libreTranslate.managed != null && + config.libreTranslate.managed === true + ) { + if (typeof config.libreTranslate.apiUrl === "string") { + set.libreTranslateApiUrl = config.libreTranslate.apiUrl; + } + if (typeof config.libreTranslate.apiKey === "string") { + set.libreTranslateApiKey = config.libreTranslate.apiKey; + } + } if (config.email.managed != null && config.email.managed === true) { set.enableEmail = true; if (typeof config.email.address === "string") { diff --git a/packages/backend/src/server/api/endpoints/admin/meta.ts b/packages/backend/src/server/api/endpoints/admin/meta.ts index c8c639f50..f0ac57892 100644 --- a/packages/backend/src/server/api/endpoints/admin/meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/meta.ts @@ -512,7 +512,8 @@ export default define(meta, paramDef, async (ps, me) => { enableGithubIntegration: instance.enableGithubIntegration, enableDiscordIntegration: instance.enableDiscordIntegration, enableServiceWorker: instance.enableServiceWorker, - translatorAvailable: instance.deeplAuthKey != null, + translatorAvailable: + instance.deeplAuthKey != null || instance.libreTranslateApiUrl != null, pinnedPages: instance.pinnedPages, pinnedClipId: instance.pinnedClipId, cacheRemoteFiles: instance.cacheRemoteFiles, @@ -564,6 +565,8 @@ export default define(meta, paramDef, async (ps, me) => { objectStorageS3ForcePathStyle: instance.objectStorageS3ForcePathStyle, deeplAuthKey: instance.deeplAuthKey, deeplIsPro: instance.deeplIsPro, + libreTranslateApiUrl: instance.libreTranslateApiUrl, + libreTranslateApiKey: instance.libreTranslateApiKey, enableIpLogging: instance.enableIpLogging, enableActiveEmailValidation: instance.enableActiveEmailValidation, }; diff --git a/packages/backend/src/server/api/endpoints/admin/update-meta.ts b/packages/backend/src/server/api/endpoints/admin/update-meta.ts index f7e79b64b..a23000732 100644 --- a/packages/backend/src/server/api/endpoints/admin/update-meta.ts +++ b/packages/backend/src/server/api/endpoints/admin/update-meta.ts @@ -124,6 +124,8 @@ export const paramDef = { summalyProxy: { type: "string", nullable: true }, deeplAuthKey: { type: "string", nullable: true }, deeplIsPro: { type: "boolean" }, + libreTranslateApiUrl: { type: "string", nullable: true }, + libreTranslateApiKey: { type: "string", nullable: true }, enableTwitterIntegration: { type: "boolean" }, twitterConsumerKey: { type: "string", nullable: true }, twitterConsumerSecret: { type: "string", nullable: true }, @@ -515,6 +517,22 @@ export default define(meta, paramDef, async (ps, me) => { set.deeplIsPro = ps.deeplIsPro; } + if (ps.libreTranslateApiUrl !== undefined) { + if (ps.libreTranslateApiUrl === "") { + set.libreTranslateApiUrl = null; + } else { + set.libreTranslateApiUrl = ps.libreTranslateApiUrl; + } + } + + if (ps.libreTranslateApiKey !== undefined) { + if (ps.libreTranslateApiKey === "") { + set.libreTranslateApiKey = null; + } else { + set.libreTranslateApiKey = ps.libreTranslateApiKey; + } + } + if (ps.enableIpLogging !== undefined) { set.enableIpLogging = ps.enableIpLogging; } diff --git a/packages/backend/src/server/api/endpoints/meta.ts b/packages/backend/src/server/api/endpoints/meta.ts index 4dc1c941e..23989750f 100644 --- a/packages/backend/src/server/api/endpoints/meta.ts +++ b/packages/backend/src/server/api/endpoints/meta.ts @@ -482,7 +482,8 @@ export default define(meta, paramDef, async (ps, me) => { enableServiceWorker: instance.enableServiceWorker, - translatorAvailable: instance.deeplAuthKey != null, + translatorAvailable: + instance.deeplAuthKey != null || instance.libreTranslateApiUrl != null, defaultReaction: instance.defaultReaction, ...(ps.detail diff --git a/packages/backend/src/server/api/endpoints/notes/translate.ts b/packages/backend/src/server/api/endpoints/notes/translate.ts index c6415ceef..d86fc12a2 100644 --- a/packages/backend/src/server/api/endpoints/notes/translate.ts +++ b/packages/backend/src/server/api/endpoints/notes/translate.ts @@ -51,15 +51,54 @@ export default define(meta, paramDef, async (ps, user) => { const instance = await fetchMeta(); - if (instance.deeplAuthKey == null) { + if (instance.deeplAuthKey == null && instance.libreTranslateApiUrl == null) { return 204; // TODO: 良い感じのエラー返す } let targetLang = ps.targetLang; if (targetLang.includes("-")) targetLang = targetLang.split("-")[0]; + if (instance.libreTranslateApiUrl != null) { + const jsonBody = { + q: note.text, + source: "auto", + target: targetLang, + format: "text", + api_key: instance.libreTranslateApiKey ?? "", + }; + + const url = new URL(instance.libreTranslateApiUrl); + if (url.pathname.endsWith("/")) { + url.pathname = url.pathname.slice(0, -1); + } + if (!url.pathname.endsWith("/translate")) { + url.pathname += "/translate"; + } + const res = await fetch(url.toString(), { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify(jsonBody), + agent: getAgentByUrl, + }); + + const json = (await res.json()) as { + detectedLanguage?: { + confidence: number; + language: string; + }; + translatedText: string; + }; + + return { + sourceLang: json.detectedLanguage?.language, + text: json.translatedText, + }; + } + const params = new URLSearchParams(); - params.append("auth_key", instance.deeplAuthKey); + params.append("auth_key", instance.deeplAuthKey ?? ""); params.append("text", note.text); params.append("target_lang", targetLang); diff --git a/packages/calckey-js/.eslintignore b/packages/calckey-js/.eslintignore deleted file mode 100644 index f22128f04..000000000 --- a/packages/calckey-js/.eslintignore +++ /dev/null @@ -1,7 +0,0 @@ -node_modules -/built -/coverage -/.eslintrc.js -/jest.config.ts -/test -/test-d diff --git a/packages/calckey-js/.eslintrc.js b/packages/calckey-js/.eslintrc.js deleted file mode 100644 index 164cf1fbe..000000000 --- a/packages/calckey-js/.eslintrc.js +++ /dev/null @@ -1,65 +0,0 @@ -module.exports = { - root: true, - parser: "@typescript-eslint/parser", - parserOptions: { - tsconfigRootDir: __dirname, - project: ["./tsconfig.json"], - }, - plugins: ["@typescript-eslint"], - extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"], - rules: { - indent: [ - "error", - "tab", - { - SwitchCase: 1, - MemberExpression: "off", - flatTernaryExpressions: true, - ArrayExpression: "first", - ObjectExpression: "first", - }, - ], - "eol-last": ["error", "always"], - semi: ["error", "always"], - quotes: ["error", "single"], - "comma-dangle": ["error", "always-multiline"], - "keyword-spacing": [ - "error", - { - before: true, - after: true, - }, - ], - "key-spacing": [ - "error", - { - beforeColon: false, - afterColon: true, - }, - ], - "space-infix-ops": ["error"], - "space-before-blocks": ["error", "always"], - "object-curly-spacing": ["error", "always"], - "nonblock-statement-body-position": ["error", "beside"], - eqeqeq: ["error", "always", { null: "ignore" }], - "no-multiple-empty-lines": ["error", { max: 1 }], - "no-multi-spaces": ["error"], - "no-var": ["error"], - "prefer-arrow-callback": ["error"], - "no-throw-literal": ["error"], - "no-param-reassign": ["warn"], - "no-constant-condition": ["warn"], - "no-empty-pattern": ["warn"], - "@typescript-eslint/no-unnecessary-condition": ["error"], - "@typescript-eslint/no-inferrable-types": ["warn"], - "@typescript-eslint/no-non-null-assertion": ["warn"], - "@typescript-eslint/explicit-function-return-type": ["warn"], - "@typescript-eslint/no-misused-promises": [ - "error", - { - checksVoidReturn: false, - }, - ], - "@typescript-eslint/consistent-type-imports": "error", - }, -}; diff --git a/packages/calckey-js/package.json b/packages/calckey-js/package.json index d68f24175..598dd1cdb 100644 --- a/packages/calckey-js/package.json +++ b/packages/calckey-js/package.json @@ -9,9 +9,8 @@ "tsd": "tsd", "api": "pnpm api-extractor run --local --verbose", "api-prod": "pnpm api-extractor run --verbose", - "eslint": "eslint . --ext .js,.jsx,.ts,.tsx", "typecheck": "tsc --noEmit", - "lint": "pnpm typecheck && pnpm eslint", + "lint": "pnpm typecheck && pnpm rome check \"src/*.ts\"", "jest": "jest --coverage --detectOpenHandles", "test": "pnpm jest && pnpm tsd" }, diff --git a/packages/client/src/components/MkFormulaCore.vue b/packages/client/src/components/MkFormulaCore.vue index 5675dbfa0..2db4c7d00 100644 --- a/packages/client/src/components/MkFormulaCore.vue +++ b/packages/client/src/components/MkFormulaCore.vue @@ -20,9 +20,12 @@ export default defineComponent({ }, computed: { compiledFormula(): any { - return katex.renderToString(this.formula, { + const katexString = katex.renderToString(this.formula, { throwOnError: false, } as any); + return this.block + ? `
${katexString}
` + : katexString; }, }, }); diff --git a/packages/client/src/components/MkNotification.vue b/packages/client/src/components/MkNotification.vue index 2c7281dbe..c909873a5 100644 --- a/packages/client/src/components/MkNotification.vue +++ b/packages/client/src/components/MkNotification.vue @@ -89,7 +89,7 @@ /> -
+
{{ i18n.ts._notification.pollEnded @@ -112,11 +112,11 @@ v-if="notification.type === 'reaction'" class="text" :to="notePage(notification.note)" - :title="summary" + :title="getNoteSummary(notification.note)" > -
@@ -275,7 +274,6 @@ import * as misskey from "calckey-js"; import XReactionIcon from "@/components/MkReactionIcon.vue"; import MkFollowButton from "@/components/MkFollowButton.vue"; import XReactionTooltip from "@/components/MkReactionTooltip.vue"; -import XShowMoreButton from "./MkShowMoreButton.vue"; import { getNoteSummary } from "@/scripts/get-note-summary"; import { notePage } from "@/filters/note"; import { userPage } from "@/filters/user"; @@ -301,19 +299,12 @@ const props = withDefaults( const elRef = ref(null); const reactionRef = ref(null); -const summary = getNoteSummary(props.notification.note); - const showEmojiReactions = defaultStore.state.enableEmojiReactions || defaultStore.state.showEmojisInReactionNotifications; const defaultReaction = ["⭐", "👍", "❤️"].includes(instance.defaultReaction) ? instance.defaultReaction : "⭐"; -const isLong = (summary.split("\n").length > 3 || summary.length > 200); -const collapsed = $ref(isLong); - - - let readObserver: IntersectionObserver | undefined; let connection; @@ -495,7 +486,6 @@ useTooltip(reactionRef, (showing) => { } > .tail { - position: relative; flex: 1; min-width: 0; @@ -536,17 +526,6 @@ useTooltip(reactionRef, (showing) => { margin-left: 4px; } } - &.collapsed > .text { - display: block; - position: relative; - max-height: calc(4em + 50px); - overflow: hidden; - mask: linear-gradient(black calc(100% - 64px), transparent); - -webkit-mask: linear-gradient( - black calc(100% - 64px), - transparent - ); - } } } diff --git a/packages/client/src/components/MkShowMoreButton.vue b/packages/client/src/components/MkShowMoreButton.vue deleted file mode 100644 index 3516d6f43..000000000 --- a/packages/client/src/components/MkShowMoreButton.vue +++ /dev/null @@ -1,68 +0,0 @@ - - - diff --git a/packages/client/src/components/MkSubNoteContent.vue b/packages/client/src/components/MkSubNoteContent.vue index 68439527a..3d6f97e8b 100644 --- a/packages/client/src/components/MkSubNoteContent.vue +++ b/packages/client/src/components/MkSubNoteContent.vue @@ -120,7 +120,6 @@ import XNoteSimple from "@/components/MkNoteSimple.vue"; import XMediaList from "@/components/MkMediaList.vue"; import XPoll from "@/components/MkPoll.vue"; import MkUrlPreview from "@/components/MkUrlPreview.vue"; -import XShowMoreButton from "./MkShowMoreButton.vue"; import XCwButton from "@/components/MkCwButton.vue"; import { extractUrlFromMfm } from "@/scripts/extract-url-from-mfm"; import { i18n } from "@/i18n"; @@ -145,7 +144,6 @@ const isLong = props.note.text != null && (props.note.text.split("\n").length > 9 || props.note.text.length > 500); const collapsed = $ref(props.note.cw == null && isLong); - const urls = props.note.text ? extractUrlFromMfm(mfm.parse(props.note.text)).slice(0, 5) : null; @@ -274,6 +272,43 @@ function focusFooter(ev) { top: 40px; } } + + :deep(.fade) { + display: block; + position: absolute; + bottom: 0; + left: 0; + width: 100%; + > span { + display: inline-block; + background: var(--panel); + padding: 0.4em 1em; + font-size: 0.8em; + border-radius: 999px; + box-shadow: 0 2px 6px rgb(0 0 0 / 20%); + } + &:hover { + > span { + background: var(--panelHighlight); + } + } + } + } + + :deep(.showLess) { + width: 100%; + margin-top: 1em; + position: sticky; + bottom: var(--stickyBottom); + + > span { + display: inline-block; + background: var(--panel); + padding: 6px 10px; + font-size: 0.8em; + border-radius: 999px; + box-shadow: 0 0 7px 7px var(--bg); + } } } } diff --git a/packages/client/src/components/MkUserPreview.vue b/packages/client/src/components/MkUserPreview.vue index ddfd39f14..1e6db1442 100644 --- a/packages/client/src/components/MkUserPreview.vue +++ b/packages/client/src/components/MkUserPreview.vue @@ -55,7 +55,20 @@ :custom-emojis="user.emojis" /> - + +
Pro account + + + + + + + + + + + + + +
@@ -422,6 +450,8 @@ let swPublicKey: any = $ref(null); let swPrivateKey: any = $ref(null); let deeplAuthKey: string = $ref(""); let deeplIsPro: boolean = $ref(false); +let libreTranslateApiUrl: string = $ref(""); +let libreTranslateApiKey: string = $ref(""); let defaultReaction: string = $ref(""); let defaultReactionCustom: string = $ref(""); @@ -456,6 +486,8 @@ async function init() { swPrivateKey = meta.swPrivateKey; deeplAuthKey = meta.deeplAuthKey; deeplIsPro = meta.deeplIsPro; + libreTranslateApiUrl = meta.libreTranslateApiUrl; + libreTranslateApiKey = meta.libreTranslateApiKey; defaultReaction = ["⭐", "👍", "❤️"].includes(meta.defaultReaction) ? meta.defaultReaction : "custom"; @@ -498,6 +530,8 @@ function save() { swPrivateKey, deeplAuthKey, deeplIsPro, + libreTranslateApiUrl, + libreTranslateApiKey, defaultReaction, }).then(() => { fetchInstance(); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9c5079f98..60e42e11a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -87,8 +87,8 @@ importers: specifier: ^4.6.4 version: 4.10.2 '@calckey/megalodon': - specifier: 5.1.24 - version: 5.1.24 + specifier: 5.2.0 + version: 5.2.0 '@discordapp/twemoji': specifier: 14.0.2 version: 14.0.2 @@ -1384,8 +1384,8 @@ packages: '@bull-board/api': 4.10.2 dev: false - /@calckey/megalodon@5.1.24: - resolution: {integrity: sha512-VRd6x8MFQ2pMF0rnGF67/GVxgp/92CV7lg2XT1wnPAfQZ1NTsjwlDQX3HewEW3fSG/r7Nzh5WbIBXC8WMWKs9g==} + /@calckey/megalodon@5.2.0: + resolution: {integrity: sha512-9MEjzKJPyd7o5bHGGlNq4oE1tMt22GUJ8o8tZXcXSpXlrSDb2rSwumirM1KXUWTW8G6NGi1leCM59gOBGLko3w==} engines: {node: '>=15.0.0'} dependencies: '@types/oauth': 0.9.1 @@ -5910,8 +5910,8 @@ packages: requiresBuild: true dev: false - /core-js@3.30.0: - resolution: {integrity: sha512-hQotSSARoNh1mYPi9O2YaWeiq/cEB95kOrFb4NCrO4RIFt1qqNpKsaE+vy/L3oiqvND5cThqXzUU3r9F7Efztg==} + /core-js@3.30.1: + resolution: {integrity: sha512-ZNS5nbiSwDTq4hFosEDqm65izl2CWmLz0hARJMyNQBgkUZMIF51cQiMvIQKA6hvuaeWxQDP3hEedM1JZIgTldQ==} requiresBuild: true dev: true @@ -15413,7 +15413,7 @@ packages: name: plyr version: 3.7.0 dependencies: - core-js: 3.30.0 + core-js: 3.30.1 custom-event-polyfill: 1.0.7 loadjs: 4.2.0 rangetouch: 2.0.1