[+] i18n framework
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
|
||||
export default {
|
||||
home: {
|
||||
titles: {
|
||||
continue: 'Continue from pause',
|
||||
history: 'History',
|
||||
myPlaylists: 'My Playlists',
|
||||
recPlaylists: 'Recommended Playlists'
|
||||
},
|
||||
btn: {
|
||||
importFromNetease: 'Import from NetEase'
|
||||
},
|
||||
text: {
|
||||
playlistCreatedBy: 'From {u}'
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
import EN from "./en"
|
||||
import ZH from "./zh"
|
||||
|
||||
type Lang = 'en' | 'zh'
|
||||
|
||||
const msgs: Record<Lang, typeof ZH> = {
|
||||
en: EN,
|
||||
zh: ZH
|
||||
}
|
||||
|
||||
let lang: Lang = 'en'
|
||||
|
||||
// Infer language from browser
|
||||
if (navigator.language.startsWith('zh')) {
|
||||
lang = 'zh'
|
||||
}
|
||||
|
||||
export const getI18n = () => msgs[lang]
|
||||
|
||||
// export function ts(key: string, variables?: { [index: string]: any }) {
|
||||
// return t(key as keyof LocalizedMessages, variables)
|
||||
// }
|
||||
|
||||
// /**
|
||||
// * Load the translation for the given key
|
||||
// *
|
||||
// * @param key
|
||||
// * @param variables
|
||||
// */
|
||||
// export function t(key: keyof LocalizedMessages, variables?: { [index: string]: any }) {
|
||||
// // Check if the key exists
|
||||
// let msg = getI18n()[key]
|
||||
// if (!msg) {
|
||||
// // Check if the key exists in English
|
||||
// if (!(msg = getI18n()[key])) {
|
||||
// msg = key
|
||||
// console.error(`ERROR!! Missing translation reference entry (English) for ${key}`)
|
||||
// }
|
||||
// else console.warn(`Missing translation for ${key} in ${lang}`)
|
||||
// }
|
||||
// // Replace variables
|
||||
// if (variables) {
|
||||
// return msg.replace(/\${(.*?)}/g, (_: string, v: string | number) => variables[v] + "")
|
||||
// }
|
||||
// return msg
|
||||
// }
|
||||
// Object.assign(window, { t })
|
||||
|
||||
|
||||
export {}
|
||||
|
||||
declare global {
|
||||
interface String {
|
||||
sed(variables: { [index: string]: any }): string
|
||||
}
|
||||
}
|
||||
|
||||
String.prototype.sed = function (variables: { [index: string]: any }) {
|
||||
return this.replace(/\${(.*?)}/g, (_: string, v: string | number) => variables[v] + "")
|
||||
}
|
||||
|
||||
Object.defineProperty(String.prototype, 'sed', { enumerable: false })
|
||||
@@ -0,0 +1,17 @@
|
||||
|
||||
export default {
|
||||
home: {
|
||||
titles: {
|
||||
continue: '从暂停的位置继续',
|
||||
history: '历史数据',
|
||||
myPlaylists: '我的歌单',
|
||||
recPlaylists: '推荐歌单'
|
||||
},
|
||||
btn: {
|
||||
importFromNetease: '从网易云导入'
|
||||
},
|
||||
text: {
|
||||
playlistCreatedBy: '{u} 创建'
|
||||
}
|
||||
}
|
||||
}
|
||||
+18
-15
@@ -1,14 +1,17 @@
|
||||
<script lang="ts">
|
||||
import AppBar from "$lib/ui/appbar/AppBar.svelte";
|
||||
import TitleHeader from "$lib/ui/TitleHeader.svelte";
|
||||
import SongInfo from "$lib/ui/listitem/SongInfo.svelte";
|
||||
import type { PageProps } from "./$types";
|
||||
import Button from "$lib/ui/Button.svelte";
|
||||
import { Layer } from "m3-svelte";
|
||||
import { goto } from "$app/navigation";
|
||||
import AppBar from "$lib/ui/appbar/AppBar.svelte"
|
||||
import TitleHeader from "$lib/ui/TitleHeader.svelte"
|
||||
import SongInfo from "$lib/ui/listitem/SongInfo.svelte"
|
||||
import type { PageProps } from "./$types"
|
||||
import Button from "$lib/ui/Button.svelte"
|
||||
import { Layer } from "m3-svelte"
|
||||
import { goto } from "$app/navigation"
|
||||
import { getI18n } from "$lib/i18n"
|
||||
|
||||
let { data }: PageProps = $props()
|
||||
|
||||
const t = getI18n().home
|
||||
|
||||
console.log(data.recPlaylists)
|
||||
|
||||
const loc = data.user.data.loc
|
||||
@@ -23,22 +26,22 @@
|
||||
<div class="vbox gap-16px overflow-y-auto flex-1">
|
||||
{#if data.last}
|
||||
<a {href}>
|
||||
<TitleHeader title="从暂停的位置继续"/>
|
||||
<TitleHeader title={t.titles.continue}/>
|
||||
<div class="p-content">
|
||||
<SongInfo info={data.last}></SongInfo>
|
||||
</div>
|
||||
</a>
|
||||
{/if}
|
||||
|
||||
<div>
|
||||
<TitleHeader title="历史数据"/>
|
||||
<!-- <div>
|
||||
<TitleHeader title={t.titles.history}/>
|
||||
<div class="p-content">
|
||||
TODO
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
|
||||
<div>
|
||||
<a href="/playlists/my"><TitleHeader title="我的歌单"/></a>
|
||||
<a href="/playlists/my"><TitleHeader title={t.titles.myPlaylists}/></a>
|
||||
<div class="p-content hbox gap-8px w-auto overflow-x-auto py-8px">
|
||||
{#each data.myPlaylists as playlist}
|
||||
<a class="vbox flex-shrink-0 gap-4px w-96px relative" href="/playlist/{playlist.id}">
|
||||
@@ -51,12 +54,12 @@
|
||||
{/each}
|
||||
</div>
|
||||
<div class="p-content">
|
||||
<a href="/import/netease"><Button icon="i-material-symbols:cloud-download-outline">从网易云导入</Button></a>
|
||||
<a href="/import/netease"><Button icon="i-material-symbols:cloud-download-outline">{t.btn.importFromNetease}</Button></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<a href="/playlists/rec"><TitleHeader title="推荐歌单"/></a>
|
||||
<a href="/playlists/rec"><TitleHeader title={t.titles.recPlaylists}/></a>
|
||||
<div class="p-content hbox gap-8px w-auto overflow-x-auto py-8px">
|
||||
{#each data.recPlaylists as playlist}
|
||||
<a class="vbox flex-shrink-0 p-8px gap-8px rounded-12px mbg-surface-container-high relative" href="/playlist/{playlist.id}">
|
||||
@@ -64,7 +67,7 @@
|
||||
<img src="{playlist.coverImgUrl}" alt="" class="size-116px rounded-8px">
|
||||
<div>
|
||||
<div class="m3-font-title-small font-bold truncate">{playlist.name}</div>
|
||||
<div class="m3-font-body-small truncate">{playlist.creator.nickname} 创建</div>
|
||||
<div class="m3-font-body-small truncate">{t.text.playlistCreatedBy.sed({u: playlist.creator.nickname})}</div>
|
||||
</div>
|
||||
</a>
|
||||
{/each}
|
||||
|
||||
Reference in New Issue
Block a user