feat: support i18n for frontmatter title/description, close #561

This commit is contained in:
YunYouJun 2025-07-12 19:24:09 +08:00
parent 89b1ce5c05
commit e537ac80b5
71 changed files with 287 additions and 142 deletions

View File

@ -81,6 +81,7 @@ declare module 'vue-router/auto-routes' {
'/posts/mermaid': RouteRecordInfo<'/posts/mermaid', '/posts/mermaid', Record<never, never>, Record<never, never>>,
'/posts/nested/a/b/c': RouteRecordInfo<'/posts/nested/a/b/c', '/posts/nested/a/b/c', Record<never, never>, Record<never, never>>,
'/posts/nested/z/': RouteRecordInfo<'/posts/nested/z/', '/posts/nested/z', Record<never, never>, Record<never, never>>,
'/posts/post-i18n': RouteRecordInfo<'/posts/post-i18n', '/posts/post-i18n', Record<never, never>, Record<never, never>>,
'/posts/post-updated': RouteRecordInfo<'/posts/post-updated', '/posts/post-updated', Record<never, never>, Record<never, never>>,
'/posts/redirect': RouteRecordInfo<'/posts/redirect', '/posts/redirect', Record<never, never>, Record<never, never>>,
'/posts/test': RouteRecordInfo<'/posts/test', '/posts/test', Record<never, never>, Record<never, never>>,

View File

@ -1,6 +1,7 @@
---
title: Code height limit
title_zh: 代码块高度限制
title:
zh-CN: 代码块高度限制
en: Code height limit
toc: true
categories:
- examples

View File

@ -1,6 +1,7 @@
---
title: Demo Sites
title_zh: 站点示例
title:
zh-CN: 站点示例
en: Demo Sites
layout: docs
categories:
- Docs

View File

@ -1,6 +1,7 @@
---
title: Markdown Styles
title_zh: Markdown 样式
title:
en: Markdown Styles
zh-CN: Markdown 样式
categories:
- Test
- Markdown

View File

@ -1,6 +1,7 @@
---
title: Markdown Extensions Test
title_zh: Markdown 扩展测试
title:
en: Markdown Extensions Test
zh-CN: Markdown 扩展测试
categories:
- Test
- Markdown

View File

@ -0,0 +1,16 @@
---
title:
zh-CN: 帖子国际化
en: Post i18n
description:
zh-CN: 帖子国际化测试描述
en: Post i18n test description
---
::: zh-CN
帖子国际化测试内容
:::
::: en
Post i18n test content
:::

View File

@ -1,6 +1,7 @@
---
title: Valaxy Addons Gallery
title_zh: Valaxy 插件橱窗
title:
en: Valaxy Addons Gallery
zh-CN: Valaxy 插件橱窗
categories:
- addon
end: false

View File

@ -1,6 +1,7 @@
---
title: Use Addon
title_zh: 使用插件
title:
zh-CN: 使用插件
en: Use Addon
categories:
- addon
---

View File

@ -1,6 +1,7 @@
---
title: Why Addon?
title_zh: 为什么需要插件?
title:
en: Why Addon?
zh-CN: 为什么需要插件?
categories:
- addon
---

View File

@ -1,6 +1,7 @@
---
title: Write an Addon
title_zh: 编写一个插件
title:
en: Write an Addon
zh-CN: 编写一个插件
categories:
- addon
end: false

View File

@ -1,6 +1,7 @@
---
title: Participate in Docs
title_zh: 参与文档
title:
en: Participate in Docs
zh-CN: 参与文档
categories:
- dev
end: false

View File

@ -1,6 +1,7 @@
---
title: FAQ
title_zh: 常见问题
title:
en: FAQ
zh-CN: 常见问题
categories:
- dev
end: false

View File

@ -1,6 +1,7 @@
---
title: Participate in Development
title_zh-CN: 参与开发
title:
en: Participate in Development
zh-CN: 参与开发
categories:
- dev
end: false

View File

@ -1,6 +1,7 @@
---
title: Client
title_zh: 客户端
title:
en: Client
zh-CN: 客户端
categories:
- ecosystem
---

View File

@ -1,6 +1,7 @@
---
title: Community
title_zh: 社区
title:
en: Community
zh-CN: 社区
categories:
- ecosystem
---

View File

@ -1,6 +1,7 @@
---
title: News
title_zh: 新闻
title:
en: News
zh-CN: 新闻
categories:
- ecosystem
---

View File

@ -1,6 +1,7 @@
---
title: VSCode Extension
title_zh: VSCode 扩展
title:
en: VSCode Extension
zh-CN: VSCode 扩展
categories:
- ecosystem
---

View File

@ -1,6 +1,7 @@
---
title: Code height limit
title_zh: 代码块高度限制
title:
zh-CN: 代码块高度限制
en: Code height limit
toc: true
categories:
- examples

View File

@ -1,6 +1,7 @@
---
title: Partial Content Encryption
title_zh: 部分内容加密
title:
en: Partial Content Encryption
zh-CN: 部分内容加密
toc: true
categories:
- examples

View File

@ -1,6 +1,7 @@
---
title: 示例站点
title_zh: 示例站点
title:
en: Example Sites
zh-CN: 示例站点
categories:
- ecosystem
---

View File

@ -1,6 +1,7 @@
---
title: FAQ
title_zh: 常见问题
title:
en: FAQ
zh-CN: 常见问题
categories:
- guide
end: false

View File

@ -1,6 +1,7 @@
---
title: Best Practice
title_zh: 最佳实践
title:
en: Best Practice
zh-CN: 最佳实践
categories:
- guide
top: 1

View File

@ -1,6 +1,7 @@
---
title: Components
title_zh: 组件
title:
en: Components
zh-CN: 组件
categories:
- guide
end: false

View File

@ -1,6 +1,7 @@
---
title: Commands
title_zh: 命令行
title:
en: Commands
zh-CN: 命令行
categories:
- guide
top: 99

View File

@ -1,6 +1,7 @@
---
title: Extend Config
title_zh: 扩展配置
title:
en: Extend Config
zh-CN: 扩展配置
categories:
- config
---

View File

@ -1,6 +1,7 @@
---
title: Config
title_zh: 基础配置
title:
en: Config
zh-CN: 基础配置
categories:
- config
end: false

View File

@ -1,6 +1,7 @@
---
title: UnoCSS Options
title_zh: UnoCSS 配置
title:
en: UnoCSS Options
zh-CN: UnoCSS 配置
categories:
- config
end: false

View File

@ -1,6 +1,7 @@
---
title: Components
title_zh: 自定义组件
title:
en: Custom Components
zh-CN: 自定义组件
categories:
- custom
end: false

View File

@ -1,6 +1,7 @@
---
title: Custom Extensions
title_zh: 自定义扩展
title:
en: Custom Extensions
zh-CN: 自定义扩展
categories:
- custom
end: false

View File

@ -1,6 +1,7 @@
---
title: Hooks
title_zh: 钩子
title:
en: Hooks
zh-CN: 钩子
categories:
- custom
end: false

View File

@ -1,6 +1,7 @@
---
title: Custom Styles
title_zh: 自定义样式
title:
en: Custom Styles
zh-CN: 自定义样式
categories:
- custom
end: false

View File

@ -1,6 +1,7 @@
---
title: Custom Post Templates
title_zh: 自定义文章模板
title:
en: Custom Post Templates
zh-CN: 自定义文章模板
categories:
- custom
end: false

View File

@ -1,6 +1,7 @@
---
title: Deployment
title_zh: 部署
title:
en: Deployment
zh-CN: 部署
categories:
- getting-started
top: 99

View File

@ -1,6 +1,7 @@
---
title: Features
title_zh: 亮点
title:
en: Features
zh-CN: 亮点
categories:
- getting-started
end: false

View File

@ -1,6 +1,7 @@
---
title: Getting Started
title_zh: 开始
title:
en: Getting Started
zh-CN: 开始
categories:
- getting-started
top: 100

View File

@ -1,6 +1,7 @@
---
title: i18n in One Page
title_zh: 单页 i18n
title:
en: i18n in One Page
zh-CN: 单页 i18n
categories:
- guide
---

View File

@ -1,6 +1,7 @@
---
title_zh: Markdown 扩展
title: Markdown Extensions
title:
en: Markdown Extensions
zh-CN: Markdown 扩展
categories:
- guide
end: false

View File

@ -1,6 +1,7 @@
---
title: Page
title_zh: 页面
title:
en: Page
zh-CN: 页面
categories:
- guide
---

View File

@ -1,6 +1,7 @@
---
title: Post
title_zh: 文章
title:
en: Post
zh-CN: 文章
categories:
- guide
end: false

View File

@ -1,6 +1,7 @@
---
title: Third Comment System
title_zh: 第三方评论系统
title:
en: Third Comment System
zh-CN: 第三方评论系统
categories:
- third
---

View File

@ -1,6 +1,7 @@
---
title: Third Party
title_zh: 第三方集成
title:
en: Third Party Integration
zh-CN: 第三方集成
categories:
- third
end: false

View File

@ -1,6 +1,7 @@
---
title: Schema.org And OPG for SEO
title_zh: Schema.org And OPG for SEO
title:
en: Schema.org And OPG for SEO
zh-CN: Schema.org 和 OPG 用于 SEO
categories:
- third
top: 0

View File

@ -1,6 +1,7 @@
---
title: Use Vite/Vue Plugin
title_zh: 使用 Vite/Vue 插件
title:
en: Use Vite/Vue Plugin
zh-CN: 使用 Vite/Vue 插件
categories:
- third
---

View File

@ -1,7 +1,8 @@
---
cover: https://cos.yunle.fun/images/bg/girl-in-water-tank.webp
title: Why Valaxy
title_zh: 为什么选 Valaxy
title:
en: Why Valaxy
zh-CN: 为什么选 Valaxy
date: 2022-03-22
categories:
- getting-started

View File

@ -1,6 +1,7 @@
---
title: Migration from Other
title_zh: 从其他博客框架迁移
title:
en: Migration from Other
zh-CN: 从其他博客框架迁移
categories:
- migration
top: 10

View File

@ -1,6 +1,7 @@
---
title: Version Migration
title_zh: 版本迁移
title:
en: Version Migration
zh-CN: 版本迁移
categories:
- migration
top: 8

View File

@ -1,6 +1,7 @@
---
title: How to realize CSS i18n?
title_zh: 如何实现 CSS i18n
title:
en: How to realize CSS i18n?
zh-CN: 如何实现 CSS i18n
date: 2022-04-09
categories: Valaxy 开发笔记
tags:

View File

@ -1,6 +1,7 @@
---
title: Valaxy Themes Gallery
title_zh: Valaxy 主题橱窗
title:
en: Valaxy Themes Gallery
zh-CN: Valaxy 主题橱窗
categories:
- theme
end: false

View File

@ -1,6 +1,7 @@
---
title: Use Theme
title_zh: 使用主题
title:
en: Use Theme
zh-CN: 使用主题
categories:
- theme
top: 100

View File

@ -1,6 +1,7 @@
---
title: How to write a theme?
title_zh: 如何编写一个 Valaxy 主题
title:
en: How to write a theme?
zh-CN: 如何编写一个 Valaxy 主题
categories:
- theme
end: false

View File

@ -1,10 +1,9 @@
<script setup lang="ts">
import { useFrontmatter, useSiteStore } from 'valaxy'
import { tObject, useFrontmatter, useSiteStore } from 'valaxy'
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
import { useRoute } from 'vue-router'
import { getLocaleTitle } from '../utils'
const frontmatter = useFrontmatter()
@ -19,7 +18,7 @@ const nextPost = computed(() => site.postList[findCurrentIndex() - 1])
const prevPost = computed(() => site.postList[findCurrentIndex() + 1])
const { locale } = useI18n()
const localeTitle = computed(() => getLocaleTitle(locale.value, frontmatter.value))
const $title = computed(() => tObject(frontmatter.value.title || '', locale.value))
</script>
<template>
@ -36,7 +35,7 @@ const localeTitle = computed(() => getLocaleTitle(locale.value, frontmatter.valu
md:text-5xl md:leading-14
"
>
{{ localeTitle }}
{{ $title }}
</h1>
</header>

View File

@ -1,6 +1,6 @@
<script lang="ts" setup>
import type { Category, Post } from 'valaxy'
import { isCategoryList } from 'valaxy'
import { isCategoryList, tObject } from 'valaxy'
import { ref } from 'vue'
import { useI18n } from 'vue-i18n'
@ -23,8 +23,7 @@ const { t, locale } = useI18n()
function getTitle(post: Post | any) {
const lang = locale.value
const localeTitle = post[`title_${lang}`] || post[`title_${lang.split('-')[0]}`]
return localeTitle || post.title
return tObject(post.title || '', lang)
}
</script>

View File

@ -1,11 +1,10 @@
<script lang="ts" setup>
import type { PageData, Post } from 'valaxy'
import { onClickHref, onContentUpdated, scrollTo, useFrontmatter, useLayout, useSidebar, useSiteConfig } from 'valaxy'
import { onClickHref, onContentUpdated, scrollTo, tObject, useFrontmatter, useLayout, useSidebar, useSiteConfig } from 'valaxy'
import { computed, nextTick } from 'vue'
import { useI18n } from 'vue-i18n'
import { useRoute, useRouter } from 'vue-router'
import { targetPadding } from '../client'
import { getLocaleTitle } from '../utils'
defineProps<{
frontmatter: Post
@ -20,7 +19,7 @@ const isHome = useLayout('home')
const layout = useLayout()
const { locale } = useI18n()
const localeTitle = computed(() => getLocaleTitle(locale.value, frontmatter.value))
const $title = computed(() => tObject(frontmatter.value.title || '', locale.value))
const route = useRoute()
const router = useRouter()
@ -64,9 +63,9 @@ onContentUpdated(() => {
<slot name="main-content-before" />
<ValaxyMd class="mx-auto w-full max-w-4xl" :frontmatter="frontmatter">
<h1 v-if="hasSidebar && !isHome && frontmatter.title" :id="frontmatter.title" tabindex="-1">
{{ localeTitle }}
<a class="header-anchor" :href="`#${frontmatter.title}`" aria-hidden="true" />
<h1 v-if="hasSidebar && !isHome && $title" :id="$title" tabindex="-1">
{{ $title }}
<a class="header-anchor" :href="`#${$title}`" aria-hidden="true" />
</h1>
<slot name="main-content-md" />
<slot />

View File

@ -1,8 +0,0 @@
/**
* get locale title
* @param locale
* @param frontmatter
*/
export function getLocaleTitle(locale: string, frontmatter: any) {
return frontmatter[`title${locale === 'en' ? '' : `_${locale}`}`] || frontmatter.title
}

View File

@ -1,6 +1,6 @@
<script setup lang="ts">
import type { Post } from 'valaxy'
import { isCategoryList } from 'valaxy'
import { isCategoryList, tObject } from 'valaxy'
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
import { useRoute } from 'vue-router'
@ -16,8 +16,7 @@ defineProps<{
*/
const { locale } = useI18n()
function getTitle(post: Post | any) {
const lang = locale.value === 'zh-CN' ? 'zh' : locale.value
return post[`title_${lang}`] ? post[`title_${lang}`] : post.title
return tObject(post.title || '', locale.value)
}
const route = useRoute()
const categoryList = computed(() => {

View File

@ -1,20 +1,23 @@
<script lang="ts" setup>
import { usePrevNext } from 'valaxy'
import { useLocaleTitle, usePrevNext } from 'valaxy'
const [prev, next] = usePrevNext()
const prevTitle = useLocaleTitle(prev)
const nextTitle = useLocaleTitle(next)
</script>
<template>
<div class="post-nav">
<div class="post-nav-item">
<RouterLink v-if="prev" class="post-nav-prev" :to="prev.path || ''" :title="prev.title">
<RouterLink v-if="prev" class="post-nav-prev" :to="prev.path || ''" :title="prevTitle">
<div class="icon" i-ri-arrow-left-s-line />
<span class="title truncate" text="sm">{{ prev.title }}</span>
<span class="title truncate" text="sm">{{ prevTitle }}</span>
</RouterLink>
</div>
<div class="post-nav-item">
<RouterLink v-if="next" :to="next.path || ''" :title="next.title" class="post-nav-next">
<span class="title truncate" text="sm">{{ next.title }}</span>
<RouterLink v-if="next" :to="next.path || ''" :title="nextTitle" class="post-nav-next">
<span class="title truncate" text="sm">{{ nextTitle }}</span>
<div class="icon" i-ri-arrow-right-s-line />
</RouterLink>
</div>

View File

@ -2,15 +2,17 @@
import { defineArticle, useSchemaOrg } from '@unhead/schema-org/vue'
import dayjs from 'dayjs'
import { useFrontmatter, useSiteConfig } from 'valaxy'
import { tObject, useFrontmatter, useSiteConfig } from 'valaxy'
import { useI18n } from 'vue-i18n'
const siteConfig = useSiteConfig()
const frontmatter = useFrontmatter()
const { locale } = useI18n()
const article: Parameters<typeof defineArticle>[0] = {
'@type': 'BlogPosting',
'headline': frontmatter.value.title,
'description': frontmatter.value.description,
'headline': tObject(frontmatter.value.title || '', locale.value),
'description': tObject(frontmatter.value.description || '', locale.value),
'author': [
{
name: siteConfig.value.author.name,

View File

@ -5,9 +5,10 @@ import { useSeoMeta } from '@unhead/vue'
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
import { tObject } from '../../../shared/utils/i18n'
import { useFrontmatter, useValaxyHead } from '../../composables'
import { useTimezone } from '../../composables/global'
import { useTimezone } from '../../composables/global'
// https://github.com/vueuse/head
// you can use this to manipulate the document head in any components,
// they will be rendered correctly in the html results with vite-ssg
@ -20,7 +21,7 @@ export function useValaxyApp() {
const { locale } = useI18n()
const title = computed(() => fm.value[`title_${locale.value}`] || fm.value.title)
const title = computed(() => tObject(fm.value.title || '', locale.value))
// seo
// todo: get first image url from markdown
@ -33,7 +34,7 @@ export function useValaxyApp() {
ogLocale: computed(() => locale.value || fm.value.lang || siteConfig.value.lang || 'en'),
ogLocaleAlternate: computed(() => siteConfig.value.languages.filter(l => l !== locale.value)),
ogSiteName: computed(() => siteConfig.value.title),
ogTitle: computed(() => fm.value.title || siteConfig.value.title),
ogTitle: computed(() => tObject(fm.value.title || siteConfig.value.title, locale.value)),
ogImage: computed(() => fm.value.ogImage || fm.value.cover || siteConfig.value.favicon),
ogType: 'website',
ogUrl: siteUrl,

View File

@ -5,15 +5,16 @@ import { useI18n } from 'vue-i18n'
import { useFrontmatter } from '../../composables'
import { useSiteConfig } from '../../config'
import { tObject } from '../../utils'
export function useValaxyHead() {
const { locale } = useI18n()
const fm = useFrontmatter()
const siteConfig = useSiteConfig()
const title = computed<string>(() => fm.value[`title_${locale.value}`] || fm.value.title)
const $title = computed(() => tObject(fm.value.title || '', locale.value))
useHead({
title,
title: $title,
titleTemplate: (title) => {
return fm.value.titleTemplate || (title ? `${title} - ${siteConfig.value.title}` : siteConfig.value.title)
},

View File

@ -1,8 +1,11 @@
import type { Ref } from 'vue'
import { isClient, useStorage } from '@vueuse/core'
import dayjs from 'dayjs'
import { computed } from 'vue'
// not optimize deps all locales
import { useI18n } from 'vue-i18n'
import { tObject } from '../../shared/utils/i18n'
import 'dayjs/locale/en'
import 'dayjs/locale/zh-cn'
@ -34,3 +37,29 @@ export function useLocale() {
toggleLocales,
}
}
/**
* get locale title
*
* ```md
* ---
* title:
* zh-CN: Valaxy - Vue
* en: Valaxy - Vue Powered Static Site Generator
* ---
* ```
*
* @param fm
*/
export function useLocaleTitle(fm: Ref<{
title?: string | Record<string, string>
} | null>) {
const { locale } = useI18n()
return computed(() => {
if (!fm.value)
return ''
const lang = locale.value
return tObject(fm.value.title || '', lang) || ''
})
}

View File

@ -3,7 +3,7 @@ import type { ComputedRef } from 'vue'
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
import { useRouterStore } from '../../stores'
import { sortByDate } from '../../utils'
import { sortByDate, tObject } from '../../utils'
export * from './usePagination'
export * from './usePrevNext'
@ -11,8 +11,7 @@ export * from './usePrevNext'
export function usePostTitle(post: ComputedRef<Post>) {
const { locale } = useI18n()
return computed(() => {
const lang = locale.value === 'zh-CN' ? 'zh' : locale.value
return post.value[`title_${lang}`] || post.value.title
return tObject(post.value.title || '', locale.value)
})
}

View File

@ -48,6 +48,8 @@ export const i18n = createI18n({
legacy: false,
locale: '',
messages: valaxyMessages,
// use key
missingWarn: false,
})
export async function install({ app, router }: ViteSSGContext, config: ComputedRef<ValaxyConfig<DefaultTheme.Config>>) {

View File

@ -1,3 +1,4 @@
export * from '../../shared'
export * from './cdn'
export * from './code'
export * from './content'
@ -5,4 +6,5 @@ export * from './helper'
export * from './router'
export * from './time'
export * from './types'
export * from './wrap'

View File

@ -16,6 +16,7 @@ import MarkdownIt from 'markdown-it'
import ora from 'ora'
import { getBorderCharacters, table } from 'table'
import { tObject } from '../../../shared'
import { matterOptions } from '../../plugins/markdown/transform/matter'
import { isExternal } from '../../utils'
import { getCreatedTime, getUpdatedTime } from '../../utils/date'
@ -36,6 +37,7 @@ export async function build(options: ResolvedValaxyOptions) {
const { config } = options
const siteConfig = config.siteConfig
const lang = siteConfig.lang || 'en'
if (!siteConfig.url || siteConfig.url === '/') {
consola.error('You must set `url` (like `https://example.com`) in `site.config.ts` to generate rss.')
@ -62,9 +64,11 @@ export async function build(options: ResolvedValaxyOptions) {
Object.keys(feedNameMap).forEach((key) => {
feedLinks[key] = `${siteUrl}${feedNameMap[key]}`
})
const title = tObject(siteConfig.title, lang)
const description = tObject(siteConfig.description, lang)
const feedOptions: FeedOptions = {
title: siteConfig.title || 'Valaxy Blog',
description: siteConfig.description,
title: title || 'Valaxy Blog',
description,
id: siteUrl || 'valaxy',
link: siteUrl,
copyright: `CC ${siteConfig.license?.type?.toUpperCase()} ${ccVersion} ${new Date().getFullYear()} © ${siteConfig.author?.name}`,
@ -172,8 +176,9 @@ export async function getPosts(params: {
}</p>`
posts.push({
title: data.title,
...data,
title: tObject(data.title, lang),
description: tObject(data.description, lang),
date: new Date(data.date),
published: new Date(data.updated || data.date),
content: html + tip,

View File

@ -45,6 +45,7 @@
"client",
"dist",
"index.d.ts",
"shared",
"shims.d.ts",
"types"
],

View File

@ -0,0 +1 @@
export * from './utils'

View File

@ -0,0 +1,17 @@
/**
* translate object
*
* { 'en': 'English', 'zh-CN': '中文' }
*
* ```ts
* tObject({ 'en': 'English', 'zh-CN': '中文' }, 'zh-CN') // 中文
* tObject({ 'en': 'English', 'zh-CN': '中文' }, 'en') // English
* tObject({ 'en': 'English', 'zh-CN': '中文' }, 'fr') // English
* ```
*/
export function tObject(data: string | Record<string, string>, lang: string): string {
if (typeof data === 'object') {
return data[lang] || Object.values(data)[0] || ''
}
return data
}

View File

@ -0,0 +1 @@
export * from './i18n'

View File

@ -44,8 +44,22 @@ export interface PageFrontMatter extends Record<string, any> {
/**
* Title
* @description
*
* ```md
* ---
* title: Post Title
* ---
* ```
*
* ```md
* ---
* title:
* en: Post Title
* zh-CN: 文章标题
* ---
* ```
*/
title: string
title: string | Record<string, string>
date: string | number | Date
/**
* Updated Time

View File

@ -1,5 +1,5 @@
export interface FuseListItem extends Record<string, any> {
title: string
title: string | Record<string, string>
excerpt?: string
author: string
tags: string[]

14
test/i18n.test.ts Normal file
View File

@ -0,0 +1,14 @@
import { describe, expect, it } from 'vitest'
import { tObject } from '../packages/valaxy/shared/utils/i18n'
describe('i18n', () => {
it('tObject with lang', () => {
const result = tObject({ 'en': 'English', 'zh-CN': '中文' }, 'zh-CN')
expect(result).toBe('中文')
})
it('tObject not found', () => {
const result = tObject({ 'en': 'English', 'zh-CN': '中文' }, 'es')
expect(result).toBe('English') // Fallback to first language
})
})