kopia lustrzana https://github.com/elk-zone/elk
				
				
				
			feat: improve posts translation logic (#1211)
							rodzic
							
								
									3b73d11fd3
								
							
						
					
					
						commit
						d745bd0583
					
				| 
						 | 
				
			
			@ -206,14 +206,6 @@ const showFavoritedAndBoostedBy = () => {
 | 
			
		|||
          />
 | 
			
		||||
        </NuxtLink>
 | 
			
		||||
 | 
			
		||||
        <CommonDropdownItem
 | 
			
		||||
          v-if="isTranslationEnabled && status.language !== languageCode"
 | 
			
		||||
          :text="translation.visible ? $t('menu.show_untranslated') : $t('menu.translate_post')"
 | 
			
		||||
          icon="i-ri:translate"
 | 
			
		||||
          :command="command"
 | 
			
		||||
          @click="toggleTranslation"
 | 
			
		||||
        />
 | 
			
		||||
 | 
			
		||||
        <template v-if="isHydrated && currentUser">
 | 
			
		||||
          <template v-if="isAuthor">
 | 
			
		||||
            <CommonDropdownItem
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -37,7 +37,10 @@ const vnode = $computed(() => {
 | 
			
		|||
    <div v-else />
 | 
			
		||||
    <template v-if="translation.visible">
 | 
			
		||||
      <div my2 h-px border="b base" bg-base />
 | 
			
		||||
      <ContentRich class="line-compact" :content="translation.text" :emojis="status.emojis" />
 | 
			
		||||
      <ContentRich v-if="translation.success" class="line-compact" :content="translation.text" :emojis="status.emojis" />
 | 
			
		||||
      <div v-else text-red-4>
 | 
			
		||||
        Error: {{ translation.error }}
 | 
			
		||||
      </div>
 | 
			
		||||
    </template>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -34,6 +34,7 @@ const isFiltered = $computed(() => filterPhrase && (context && context !== 'deta
 | 
			
		|||
        <p>{{ status.spoilerText }}</p>
 | 
			
		||||
      </template>
 | 
			
		||||
      <StatusBody v-if="!status.sensitive || status.spoilerText" :status="status" :with-action="!isDetails" :class="isDetails ? 'text-xl' : ''" />
 | 
			
		||||
      <StatusTranslation :status="status" />
 | 
			
		||||
      <StatusPoll v-if="status.poll" :status="status" />
 | 
			
		||||
      <StatusMedia
 | 
			
		||||
        v-if="status.mediaAttachments?.length"
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,41 @@
 | 
			
		|||
<script setup lang="ts">
 | 
			
		||||
import type { mastodon } from 'masto'
 | 
			
		||||
 | 
			
		||||
const { status } = defineProps<{
 | 
			
		||||
  status: mastodon.v1.Status
 | 
			
		||||
}>()
 | 
			
		||||
 | 
			
		||||
const {
 | 
			
		||||
  toggle: _toggleTranslation,
 | 
			
		||||
  translation,
 | 
			
		||||
  enabled: isTranslationEnabled,
 | 
			
		||||
} = useTranslation(status)
 | 
			
		||||
 | 
			
		||||
let translating = $ref(false)
 | 
			
		||||
const toggleTranslation = async () => {
 | 
			
		||||
  translating = true
 | 
			
		||||
  try {
 | 
			
		||||
    await _toggleTranslation()
 | 
			
		||||
  }
 | 
			
		||||
  finally {
 | 
			
		||||
    translating = false
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
</script>
 | 
			
		||||
 | 
			
		||||
<template>
 | 
			
		||||
  <div>
 | 
			
		||||
    <button
 | 
			
		||||
      v-if="isTranslationEnabled && status.language !== languageCode" pl-0 flex="~ center" gap-2
 | 
			
		||||
      :disabled="translating" disabled-bg-transparent btn-text @click="toggleTranslation"
 | 
			
		||||
    >
 | 
			
		||||
      <span v-if="translating" block animate-spin preserve-3d>
 | 
			
		||||
        <span block i-ri:loader-2-fill />
 | 
			
		||||
      </span>
 | 
			
		||||
      <div v-else i-ri:translate />
 | 
			
		||||
      {{ translation.visible ? $t('menu.show_untranslated') : $t('menu.translate_post') }}
 | 
			
		||||
    </button>
 | 
			
		||||
  </div>
 | 
			
		||||
</template>
 | 
			
		||||
 | 
			
		||||
<style scoped></style>
 | 
			
		||||
| 
						 | 
				
			
			@ -11,24 +11,37 @@ export interface TranslationResponse {
 | 
			
		|||
export const languageCode = process.server ? 'en' : navigator.language.replace(/-.*$/, '')
 | 
			
		||||
export async function translateText(text: string, from?: string | null, to?: string) {
 | 
			
		||||
  const config = useRuntimeConfig()
 | 
			
		||||
  const { translatedText } = await $fetch<TranslationResponse>(config.public.translateApi, {
 | 
			
		||||
    method: 'POST',
 | 
			
		||||
    body: {
 | 
			
		||||
      q: text,
 | 
			
		||||
      source: from ?? 'auto',
 | 
			
		||||
      target: to ?? languageCode,
 | 
			
		||||
      format: 'html',
 | 
			
		||||
      api_key: '',
 | 
			
		||||
    },
 | 
			
		||||
  const status = $ref({
 | 
			
		||||
    success: false,
 | 
			
		||||
    error: '',
 | 
			
		||||
    text: '',
 | 
			
		||||
  })
 | 
			
		||||
  return translatedText
 | 
			
		||||
  try {
 | 
			
		||||
    const response = await $fetch<TranslationResponse>(config.public.translateApi, {
 | 
			
		||||
      method: 'POST',
 | 
			
		||||
      body: {
 | 
			
		||||
        q: text,
 | 
			
		||||
        source: from ?? 'auto',
 | 
			
		||||
        target: to ?? languageCode,
 | 
			
		||||
        format: 'html',
 | 
			
		||||
        api_key: '',
 | 
			
		||||
      },
 | 
			
		||||
    })
 | 
			
		||||
    status.success = true
 | 
			
		||||
    status.text = response.translatedText
 | 
			
		||||
  }
 | 
			
		||||
  catch (err) {
 | 
			
		||||
    // TODO: improve type
 | 
			
		||||
    status.error = (err as { data: { error: string } }).data.error
 | 
			
		||||
  }
 | 
			
		||||
  return status
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const translations = new WeakMap<mastodon.v1.Status | mastodon.v1.StatusEdit, { visible: boolean; text: string }>()
 | 
			
		||||
const translations = new WeakMap<mastodon.v1.Status | mastodon.v1.StatusEdit, { visible: boolean; text: string; success: boolean; error: string }>()
 | 
			
		||||
 | 
			
		||||
export function useTranslation(status: mastodon.v1.Status | mastodon.v1.StatusEdit) {
 | 
			
		||||
  if (!translations.has(status))
 | 
			
		||||
    translations.set(status, reactive({ visible: false, text: '' }))
 | 
			
		||||
    translations.set(status, reactive({ visible: false, text: '', success: false, error: '' }))
 | 
			
		||||
 | 
			
		||||
  const translation = translations.get(status)!
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -36,8 +49,12 @@ export function useTranslation(status: mastodon.v1.Status | mastodon.v1.StatusEd
 | 
			
		|||
    if (!('language' in status))
 | 
			
		||||
      return
 | 
			
		||||
 | 
			
		||||
    if (!translation.text)
 | 
			
		||||
      translation.text = await translateText(status.content, status.language)
 | 
			
		||||
    if (!translation.text) {
 | 
			
		||||
      const { success, text, error } = await translateText(status.content, status.language)
 | 
			
		||||
      translation.error = error
 | 
			
		||||
      translation.text = text
 | 
			
		||||
      translation.success = success
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    translation.visible = !translation.visible
 | 
			
		||||
  }
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -92,6 +92,7 @@ export default defineNuxtConfig({
 | 
			
		|||
      env: '', // set in build-env module
 | 
			
		||||
      buildInfo: {} as BuildInfo, // set in build-env module
 | 
			
		||||
      pwaEnabled: !isDevelopment || process.env.VITE_DEV_PWA === 'true',
 | 
			
		||||
      // We use LibreTranslate(https://github.com/LibreTranslate/LibreTranslate) as our default translation server #76
 | 
			
		||||
      translateApi: '',
 | 
			
		||||
      defaultServer: 'mas.to',
 | 
			
		||||
    },
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Ładowanie…
	
		Reference in New Issue