Reorganize translation interfaces/files

This commit is contained in:
Alex Gleason 2024-10-10 14:06:04 -05:00
parent 874da1baad
commit d639d9a14d
No known key found for this signature in database
GPG key ID: 7211D1F99744FBB7
8 changed files with 71 additions and 76 deletions

View file

@ -120,6 +120,7 @@ import { indexController } from '@/controllers/site.ts';
import { manifestController } from '@/controllers/manifest.ts';
import { nodeInfoController, nodeInfoSchemaController } from '@/controllers/well-known/nodeinfo.ts';
import { nostrController } from '@/controllers/well-known/nostr.ts';
import { DittoTranslator } from '@/interfaces/DittoTranslator.ts';
import { auth98Middleware, requireProof, requireRole } from '@/middleware/auth98Middleware.ts';
import { cspMiddleware } from '@/middleware/cspMiddleware.ts';
import { metricsMiddleware } from '@/middleware/metricsMiddleware.ts';
@ -129,7 +130,6 @@ import { requireSigner } from '@/middleware/requireSigner.ts';
import { signerMiddleware } from '@/middleware/signerMiddleware.ts';
import { storeMiddleware } from '@/middleware/storeMiddleware.ts';
import { uploaderMiddleware } from '@/middleware/uploaderMiddleware.ts';
import { DittoTranslator } from '@/translators/translator.ts';
import { translatorMiddleware } from '@/middleware/translatorMiddleware.ts';
interface AppEnv extends HonoEnv {

View file

@ -0,0 +1,16 @@
import { LanguageCode } from 'iso-639-1';
import { LRUCache } from 'lru-cache';
import { MastodonTranslation } from '@/entities/MastodonTranslation.ts';
import { Time } from '@/utils/time.ts';
/** Entity returned by DittoTranslator and LRUCache */
interface DittoTranslation {
data: MastodonTranslation;
}
/** Translations LRU cache. */
export const translationCache = new LRUCache<`${LanguageCode}-${string}`, DittoTranslation>({
max: 1000,
ttl: Time.hours(6),
});

View file

@ -2,10 +2,11 @@ import { LanguageCode } from 'iso-639-1';
import { z } from 'zod';
import { AppController } from '@/app.ts';
import { localeSchema } from '@/schema.ts';
import { dittoTranslations, dittoTranslationsKey, MastodonTranslation } from '@/translators/translator.ts';
import { parseBody } from '@/utils/api.ts';
import { translationCache } from '@/caches/translationCache.ts';
import { MastodonTranslation } from '@/entities/MastodonTranslation.ts';
import { getEvent } from '@/queries.ts';
import { localeSchema } from '@/schema.ts';
import { parseBody } from '@/utils/api.ts';
import { renderStatus } from '@/views/mastodon/statuses.ts';
const translateSchema = z.object({
@ -45,11 +46,11 @@ const translateController: AppController = async (c) => {
return c.json({ error: 'Bad request.', schema: result.error }, 400);
}
const translatedId = `${lang}-${id}` as dittoTranslationsKey;
const translationCache = dittoTranslations.get(translatedId);
const cacheKey: `${LanguageCode}-${string}` = `${lang}-${id}`;
const cached = translationCache.get(cacheKey);
if (translationCache) {
return c.json(translationCache.data, 200);
if (cached) {
return c.json(cached.data, 200);
}
const mediaAttachments = status?.media_attachments.map((value) => {
@ -68,7 +69,7 @@ const translateController: AppController = async (c) => {
media_attachments: [],
poll: null,
detected_source_language: event.language ?? 'en',
provider: translator.getProvider(),
provider: translator.provider,
};
if ((status?.poll as MastodonTranslation['poll'])?.options) {
@ -130,10 +131,10 @@ const translateController: AppController = async (c) => {
mastodonTranslation.detected_source_language = data.source_lang;
dittoTranslations.set(translatedId, { data: mastodonTranslation });
translationCache.set(cacheKey, { data: mastodonTranslation });
return c.json(mastodonTranslation, 200);
} catch (e) {
if (e instanceof Error && e.message?.includes('not supported')) {
if (e instanceof Error && e.message.includes('not supported')) {
return c.json({ error: `Translation of source language '${event.language}' not supported` }, 422);
}
return c.json({ error: 'Service Unavailable' }, 503);

View file

@ -0,0 +1,17 @@
import { LanguageCode } from 'iso-639-1';
/** https://docs.joinmastodon.org/entities/Translation/ */
export interface MastodonTranslation {
/** HTML-encoded translated content of the status. */
content: string;
/** The translated spoiler warning of the status. */
spoiler_text: string;
/** The translated media descriptions of the status. */
media_attachments: { id: string; description: string }[];
/** The translated poll of the status. */
poll: { id: string; options: { title: string }[] } | null;
//** The language of the source text, as auto-detected by the machine translation provider. */
detected_source_language: LanguageCode;
/** The service that provided the machine translation. */
provider: string;
}

View file

@ -0,0 +1,18 @@
import type { LanguageCode } from 'iso-639-1';
/** DittoTranslator class, used for status translation. */
export interface DittoTranslator {
/** Translate the 'content' into 'targetLanguage'. */
translate(
/** Texts to translate. */
texts: string[],
/** The language of the source texts. */
sourceLanguage: LanguageCode | undefined,
/** The texts will be translated into this language. */
targetLanguage: LanguageCode,
/** Custom options. */
opts?: { signal?: AbortSignal },
): Promise<{ results: string[]; source_lang: LanguageCode }>;
/** Provider name, eg `DeepL.com` */
provider: string;
}

View file

@ -1,7 +1,7 @@
import { LanguageCode } from 'iso-639-1';
import { z } from 'zod';
import { DittoTranslator, SourceLanguage, TargetLanguage } from '@/translators/translator.ts';
import { DittoTranslator } from '@/interfaces/DittoTranslator.ts';
import { languageSchema } from '@/schema.ts';
interface DeepLTranslatorOpts {
@ -28,8 +28,8 @@ export class DeepLTranslator implements DittoTranslator {
async translate(
texts: string[],
source: SourceLanguage | undefined,
dest: TargetLanguage,
source: LanguageCode | undefined,
dest: LanguageCode,
opts?: { signal?: AbortSignal },
) {
const { translations } = await this.translateMany(texts, source, dest, opts);
@ -43,8 +43,8 @@ export class DeepLTranslator implements DittoTranslator {
/** DeepL translate request. */
private async translateMany(
texts: string[],
source: SourceLanguage | undefined,
targetLanguage: TargetLanguage,
source: LanguageCode | undefined,
targetLanguage: LanguageCode,
opts?: { signal?: AbortSignal },
) {
const body: any = {

View file

@ -1,7 +1,7 @@
import { LanguageCode } from 'iso-639-1';
import { z } from 'zod';
import { DittoTranslator, SourceLanguage, TargetLanguage } from '@/translators/translator.ts';
import { DittoTranslator } from '@/interfaces/DittoTranslator.ts';
import { languageSchema } from '@/schema.ts';
interface LibreTranslateTranslatorOpts {
@ -28,8 +28,8 @@ export class LibreTranslateTranslator implements DittoTranslator {
async translate(
texts: string[],
source: SourceLanguage | undefined,
dest: TargetLanguage,
source: LanguageCode | undefined,
dest: LanguageCode,
opts?: { signal?: AbortSignal },
) {
const translations = await Promise.all(

View file

@ -1,57 +0,0 @@
import { LanguageCode } from 'iso-639-1';
import { LRUCache } from 'lru-cache';
import { Time } from '@/utils/time.ts';
/** Original language of the post */
export type SourceLanguage = LanguageCode;
/** Content will be translated to this language */
export type TargetLanguage = LanguageCode;
/** Entity returned by DittoTranslator and LRUCache */
type DittoTranslation = {
data: MastodonTranslation;
};
export type MastodonTranslation = {
/** HTML-encoded translated content of the status. */
content: string;
/** The translated spoiler warning of the status. */
spoiler_text: string;
/** The translated media descriptions of the status. */
media_attachments: { id: string; description: string }[];
/** The translated poll of the status. */
poll: { id: string; options: { title: string }[] } | null;
//** The language of the source text, as auto-detected by the machine translation provider. */
detected_source_language: SourceLanguage;
/** The service that provided the machine translation. */
provider: string;
};
/** DittoTranslator class, used for status translation. */
export interface DittoTranslator {
/** Translate the 'content' into 'targetLanguage'. */
translate(
texts: string[],
/** The language of the source text/status. */
sourceLanguage: SourceLanguage | undefined,
/** The status content will be translated into this language. */
targetLanguage: TargetLanguage,
/** Custom options. */
opts?: { signal?: AbortSignal },
): Promise<{ results: string[]; source_lang: SourceLanguage }>;
/** Provider name, eg `DeepL.com` */
provider: string;
}
/** Includes the TARGET language and the status id.
* Example: en-390f5b01b49a8ee6e13fe917420c023d889b3da8e983a14c9e84587e43d12c15
* The example above means:
* I want the status 390f5b01b49a8ee6e13fe917420c023d889b3da8e983a14c9e84587e43d12c15 translated to english (if it exists in the LRUCache). */
export type dittoTranslationsKey = `${TargetLanguage}-${string}`;
export const dittoTranslations = new LRUCache<dittoTranslationsKey, DittoTranslation>({
max: 1000,
ttl: Time.hours(6),
});