Skip to content

Commit

Permalink
feat: display translations that are not the same as i18n locale (#73)
Browse files Browse the repository at this point in the history
* feat: display translations that are not the same as i18n locale

* feat: add separate prop `translationLocale`

* feat: display translations that are not the same as i18n locale

* chore: lint

---------

Co-authored-by: Anthony Fu <[email protected]>
  • Loading branch information
donaldxdonald and antfu authored Oct 25, 2024
1 parent fea0f73 commit dba34fc
Show file tree
Hide file tree
Showing 14 changed files with 124 additions and 20 deletions.
2 changes: 1 addition & 1 deletion app/components/LyricsLine.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ watchEffect(async () => {
translation.value = ''
return
}
const matched = props.line.trans?.[locale.value]
const matched = props.line.trans?.[settings.value.translationLocale || locale.value]
if (matched) {
translation.value = matched
return
Expand Down
7 changes: 3 additions & 4 deletions app/components/SettingsDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,9 @@ const { t, locale, locales, setLocale } = useI18n()
icon="i-uil-letter-english-a"
:title="t('settings.displayRomaji')"
/>
<ToggleButton
v-model="settings.translation"
icon="i-uil-english-to-chinese"
:title="t('settings.displayTranslation')"
<TranslationSelector
type="toggle-button"
:song
/>
<ToggleButton
v-model="settings.follow"
Expand Down
16 changes: 8 additions & 8 deletions app/components/SettingsFloat.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
<script setup lang="ts">
import type { MaruSongDataParsed } from '@marure/schema'
import { Menu, Tooltip } from 'floating-vue'
import { useSettings } from '~/composables/settings'
defineProps<{
song: MaruSongDataParsed
}>()
const settings = useSettings()
</script>

Expand Down Expand Up @@ -58,14 +62,10 @@ const settings = useSettings()
</div>
</template>
</Tooltip>
<Tooltip placement="top">
<IconToggle v-model="settings.translation" icon="i-uil-english-to-chinese" />
<template #popper>
<div>
{{ $t("settings.displayTranslation") }}
</div>
</template>
</Tooltip>
<TranslationSelector
type="toggle"
:song
/>
<Menu placement="top">
<IconButton
:class="settings.fontSize.toString() === '1' ? 'op40 @hover:color-base! @hover:op100' : 'color-primary'"
Expand Down
2 changes: 1 addition & 1 deletion app/components/SongPlay.vue
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ onMounted(() => {
</div>

<div pointer-events-auto absolute left-3 right-3 top-3 z-floating flex>
<SettingsFloat mxa lt-lg="hidden" />
<SettingsFloat mxa lt-lg="hidden" :song="song" />
</div>
</LyricsTrack>
<ModalPopup v-model="showInfoModal" dialog-class="max-h-90vh! p4">
Expand Down
49 changes: 49 additions & 0 deletions app/components/TranslationSelector.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<script setup lang="ts">
import type { MaruSongDataParsed } from '@marure/schema'
import { Menu } from 'floating-vue'
const props = defineProps<{
type: 'toggle-button' | 'toggle'
song?: MaruSongDataParsed
}>()
const settings = useSettings()
const { locales } = useI18n()
const {
translations,
translationsEnabled,
setTranslationLocale,
toggleTranslation,
} = useTranslationSettings(() => props.song)
</script>

<template>
<Menu placement="bottom">
<ActionButton
icon="i-uil-english-to-chinese"
:type="type"
:active="translationsEnabled"
:title="type === 'toggle-button' ? $t('settings.displayTranslation') : undefined"
@click="toggleTranslation"
/>
<template #popper>
<div px4 py3 flex="~ col gap-2">
<div v-if="!translations.length" op75>
{{ $t('messages.noTranslations') }}
</div>
<template v-else>
<div>
{{ $t('settings.displayTranslation') }}
</div>
<ToggleButton
v-for="trans in translations" :key="trans"
:model-value="settings.translationLocale === trans && settings.translation"
:title="locales.find(l => l.code === trans)?.name || trans"
@click="setTranslationLocale(trans)"
/>
</template>
</div>
</template>
</Menu>
</template>
7 changes: 6 additions & 1 deletion app/components/atomic/ActionButton.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script setup lang="ts">
const props = withDefaults(
defineProps<{
type?: 'icon' | 'button' | 'toggle'
type?: 'icon' | 'button' | 'toggle' | 'toggle-button'
title?: string
icon: string
}>(),
Expand All @@ -27,4 +27,9 @@ const toggleActive = defineModel<boolean>('active')
v-bind="props"
v-model="toggleActive"
/>
<ToggleButton
v-else-if="props.type === 'toggle-button'"
v-bind="props"
v-model="toggleActive"
/>
</template>
3 changes: 2 additions & 1 deletion app/components/editors/SongEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@ function syncLrc() {
stateRef.value.lrc = serializeToLrc({ lyrics: stateRef.value.lyrics, meta: {} })
}
else if (dirtyLyrics.value === 'lyrics') {
stateRef.value.lyrics = parseLrc(stateRef.value.lrc).lyrics
const parsed = parseLrc(stateRef.value.lrc)
stateRef.value.lyrics = parsed.lyrics
}
dirtyLyrics.value = 'none'
nextTick(() => resume())
Expand Down
44 changes: 44 additions & 0 deletions app/composables/settings.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,49 @@
import type { MaruSongDataParsed } from '@marure/schema'
import { _settings } from '~/state/local-storage'

export function useSettings() {
return _settings
}

export function useTranslationSettings(song: MaybeRefOrGetter<MaruSongDataParsed | undefined>) {
const settings = useSettings()

const translations = computed(() => {
const _song = toValue(song)
if (!_song)
return []

const locales = new Set<string>()
for (const line of _song.lyrics) {
for (const [key, value] of Object.entries(line.trans ?? {})) {
if (value?.trim())
locales.add(key)
}
}

return Array.from(locales)
})

const translationsEnabled = computed(() => settings.value.translation && translations.value.includes(settings.value.translationLocale))

function toggleTranslation() {
settings.value.translation = !settings.value.translation
}

function setTranslationLocale(localeCode: string) {
if (settings.value.translationLocale === localeCode && settings.value.translation) {
settings.value.translation = false
}
else {
settings.value.translationLocale = localeCode
settings.value.translation = true
}
}

return {
translations,
translationsEnabled,
toggleTranslation,
setTranslationLocale,
}
}
3 changes: 2 additions & 1 deletion app/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,8 @@
"messages": {
"wip": "The website is under development, and many features are not yet complete. Welcome to report issues via Discord",
"fromShare": "from share link",
"contentMissingTranslations": "There is currently no corresponding translation for this content, please consider using machine translation."
"contentMissingTranslations": "There is currently no corresponding translation for this content, please consider using machine translation.",
"noTranslations": "Lyrics not yet translated"
},
"appname": "二重丸",
"errors": {
Expand Down
3 changes: 2 additions & 1 deletion app/locales/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,8 @@
"messages": {
"fromShare": "共有リンクから",
"wip": "ウェブサイトは開発中で、多くの機能がまだ完成していません。問題があったらDiscordで報告してください",
"contentMissingTranslations": "このドキュメントにはまだ対応する翻訳がありません。機械翻訳の使用をご検討ください。"
"contentMissingTranslations": "このドキュメントにはまだ対応する翻訳がありません。機械翻訳の使用をご検討ください。",
"noTranslations": "歌詞はまだ翻訳されていません"
},
"actions": {
"favorite": "お気に入りに追加",
Expand Down
3 changes: 2 additions & 1 deletion app/locales/zh-Hans.json
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,8 @@
"messages": {
"wip": "网站开发中、许多功能尚未完善。欢迎通过 Discord 回报问题",
"fromShare": "来自分享连结",
"contentMissingTranslations": "这个文档暂时没有对应的翻译,请考虑使用机器翻译。"
"contentMissingTranslations": "这个文档暂时没有对应的翻译,请考虑使用机器翻译。",
"noTranslations": "歌词暂无翻译"
},
"appname": "二重丸",
"errors": {
Expand Down
3 changes: 2 additions & 1 deletion app/locales/zh-Hant.json
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,8 @@
"messages": {
"fromShare": "來自分享連結",
"wip": "網站開發中、許多功能尚未完善。歡迎透過 Discord 回報問題",
"contentMissingTranslations": "這個文檔暫時沒有對應的翻譯,請考慮使用機器翻譯。"
"contentMissingTranslations": "這個文檔暫時沒有對應的翻譯,請考慮使用機器翻譯。",
"noTranslations": "歌詞暫無翻譯"
},
"actions": {
"favorite": "收藏歌曲",
Expand Down
1 change: 1 addition & 0 deletions app/state/local-storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const _settings = useLocalStorage<UiSettings>(
kanji: true,
furigana: true,
translation: true,
translationLocale: '',
follow: true,
autoPause: false,
speed: 1,
Expand Down
1 change: 1 addition & 0 deletions app/types/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export interface UiSettings {
kanji: boolean
furigana: boolean
translation: boolean
translationLocale: string
follow: boolean
autoPause: boolean
speed: number
Expand Down

0 comments on commit dba34fc

Please sign in to comment.