@coffic/cosy-ui 0.5.4 → 0.5.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/errors/404.astro +6 -4
- package/dist/components/layouts/AppLayout.astro +3 -3
- package/dist/components/layouts/BaseLayout.astro +1 -1
- package/dist/components/layouts/Footer.astro +14 -9
- package/dist/components/layouts/Sidebar.astro +56 -0
- package/dist/components/navigation/TableOfContents.astro +3 -3
- package/dist/index.ts +2 -1
- package/dist/integration.ts +4 -4
- package/dist/style.ts +2 -1
- package/dist/types/footer.ts +130 -135
- package/dist/types/header.ts +50 -55
- package/dist/utils/i18n.ts +57 -59
- package/dist/utils/lang_package.ts +222 -0
- package/dist/utils/language.ts +113 -162
- package/package.json +2 -2
@@ -3,8 +3,10 @@ import { LinkUtil } from '../../utils/link';
|
|
3
3
|
const baseUrl = LinkUtil.getBaseUrl();
|
4
4
|
---
|
5
5
|
|
6
|
-
<div class="flex flex-col
|
7
|
-
<
|
8
|
-
|
9
|
-
|
6
|
+
<div class="flex flex-col items-center justify-center h-screen">
|
7
|
+
<div class="flex flex-col justify-center items-center min-h-[50vh] text-center">
|
8
|
+
<h1 class="mb-4 font-bold text-4xl">404 - 页面未找到</h1>
|
9
|
+
<p class="mb-8 text-lg">抱歉,您要找的文档不存在。</p>
|
10
|
+
<a href={baseUrl} class="btn btn-primary"> 返回首页 </a>
|
11
|
+
</div>
|
10
12
|
</div>
|
@@ -202,23 +202,23 @@ const {
|
|
202
202
|
head={metaConfig.head}
|
203
203
|
debug={debug}
|
204
204
|
{...rest}>
|
205
|
+
<ClientRouter />
|
205
206
|
{showHeader && <Header {...headerConfig} debug={debug} transition:persist />}
|
206
207
|
|
207
208
|
<Container flex="row" gap="md" size="full" padding="none">
|
208
209
|
<!-- 侧边栏容器 -->
|
209
|
-
{showSidebar && <Sidebar {...sidebarConfig} />}
|
210
|
+
{showSidebar && <Sidebar {...sidebarConfig} transition:name="sidebar" transition:persist />}
|
210
211
|
|
211
212
|
<!-- 主内容区域 -->
|
212
213
|
<Main {...mainContentConfig}>
|
213
214
|
<slot />
|
214
|
-
<ClientRouter />
|
215
215
|
</Main>
|
216
216
|
</Container>
|
217
217
|
|
218
218
|
<!-- Footer -->
|
219
219
|
{
|
220
220
|
showFooter && (
|
221
|
-
<Container size="full" padding="none">
|
221
|
+
<Container size="full" padding="none" transition:persist>
|
222
222
|
<Footer {...footerConfig} />
|
223
223
|
</Container>
|
224
224
|
)
|
@@ -82,7 +82,7 @@ let bodyClasses = debug ? 'cosy:border cosy:border-red-500' : className || '';
|
|
82
82
|
{description && <meta name="description" content={description} />}
|
83
83
|
{keywords && <meta name="keywords" content={keywords} />}
|
84
84
|
<meta name="generator" content={Astro.generator} />
|
85
|
-
<link rel="icon" type="image/svg+xml" href="/favicon.
|
85
|
+
<link rel="icon" type="image/svg+xml" href="/favicon.png" />
|
86
86
|
|
87
87
|
<!-- 自定义样式 -->
|
88
88
|
{customStyles && <style set:html={customStyles} />}
|
@@ -178,13 +178,12 @@ const {
|
|
178
178
|
mediaLink,
|
179
179
|
techStackLink,
|
180
180
|
debug = false,
|
181
|
-
lang: userLang,
|
182
181
|
} = Astro.props as FooterProps;
|
183
182
|
|
184
183
|
// 获取当前语言
|
185
|
-
const
|
184
|
+
const lang = LanguageUtil.getCurrentLanguage(Astro);
|
186
185
|
// 创建文本获取函数
|
187
|
-
const t = createTextGetter(
|
186
|
+
const t = createTextGetter(lang, 'footer');
|
188
187
|
|
189
188
|
const currentYear = new Date().getFullYear();
|
190
189
|
|
@@ -211,12 +210,14 @@ const debugClasses = debug
|
|
211
210
|
class:list={[
|
212
211
|
'cosy:footer cosy:z-50 cosy:sm:footer-horizontal cosy:bg-base-200 cosy:text-base-content cosy:p-10',
|
213
212
|
debugClasses.footer,
|
214
|
-
]}
|
213
|
+
]}
|
214
|
+
>
|
215
215
|
<div
|
216
216
|
class:list={[
|
217
217
|
'cosy:flex cosy:flex-col cosy:md:h-56 cosy:gap-8 cosy:container cosy:mx-auto cosy:items-center cosy:w-full cosy:md:flex-row cosy:md:justify-between',
|
218
218
|
debugClasses.section,
|
219
|
-
]}
|
219
|
+
]}
|
220
|
+
>
|
220
221
|
{/* 品牌区域 */}
|
221
222
|
<aside class:list={['cosy:max-w-xs cosy:text-center', debugClasses.aside]}>
|
222
223
|
<a href={homeLink} class="cosy:flex cosy:items-center cosy:gap-2 cosy:mb-4 cosy:no-underline">
|
@@ -247,7 +248,8 @@ const debugClasses = debug
|
|
247
248
|
class="cosy:btn cosy:btn-circle cosy:btn-ghost cosy:btn-sm"
|
248
249
|
target="_blank"
|
249
250
|
rel="noopener noreferrer"
|
250
|
-
aria-label={link.name}
|
251
|
+
aria-label={link.name}
|
252
|
+
>
|
251
253
|
<SocialIcon platform={link.platform} />
|
252
254
|
</a>
|
253
255
|
))}
|
@@ -261,7 +263,8 @@ const debugClasses = debug
|
|
261
263
|
class:list={[
|
262
264
|
'cosy:flex cosy:h-full cosy:flex-col cosy:justify-center cosy:gap-8 cosy:mx-auto cosy:max-w-xl cosy:text-center cosy:items-center cosy:w-full cosy:md:flex-row cosy:md:justify-between cosy:md:items-start',
|
263
265
|
debugClasses.section,
|
264
|
-
]}
|
266
|
+
]}
|
267
|
+
>
|
265
268
|
{/* 产品导航 */}
|
266
269
|
{products.length > 0 && <NavSection title={t('products')} links={products} />}
|
267
270
|
|
@@ -325,7 +328,8 @@ const debugClasses = debug
|
|
325
328
|
class:list={[
|
326
329
|
'cosy:p-4 cosy:bg-primary cosy:text-primary-content cosy:w-full',
|
327
330
|
debugClasses.aside,
|
328
|
-
]}
|
331
|
+
]}
|
332
|
+
>
|
329
333
|
<p class="cosy:text-center">{inspirationalSlogan}</p>
|
330
334
|
</aside>
|
331
335
|
)
|
@@ -336,7 +340,8 @@ const debugClasses = debug
|
|
336
340
|
class:list={[
|
337
341
|
'cosy:footer cosy:footer-center cosy:p-4 cosy:bg-base-300 cosy:text-base-content',
|
338
342
|
debugClasses.footer,
|
339
|
-
]}
|
343
|
+
]}
|
344
|
+
>
|
340
345
|
<aside class:list={['cosy:items-center cosy:grid-flow-col', debugClasses.aside]}>
|
341
346
|
<p class="cosy:opacity-70 cosy:text-sm">
|
342
347
|
© {currentYear}
|
@@ -117,3 +117,59 @@ const currentSection = sidebarItems.find((section) =>
|
|
117
117
|
<SidebarNav sidebarItems={sidebarItems} currentPath={currentPath} debug={debug} />
|
118
118
|
</div>
|
119
119
|
</aside>
|
120
|
+
|
121
|
+
<script>
|
122
|
+
// 处理侧边栏滚动位置保存和恢复
|
123
|
+
document.addEventListener('astro:before-preparation', () => {
|
124
|
+
// 获取桌面侧边栏滚动容器
|
125
|
+
const desktopSidebarContent = document.querySelector(
|
126
|
+
'aside[data-sidebar] .cosy\\:overflow-y-auto'
|
127
|
+
);
|
128
|
+
|
129
|
+
// 保存滚动位置到localStorage
|
130
|
+
if (desktopSidebarContent) {
|
131
|
+
localStorage.setItem('sidebarScrollPosition', desktopSidebarContent.scrollTop.toString());
|
132
|
+
}
|
133
|
+
|
134
|
+
// 获取移动端侧边栏滚动容器
|
135
|
+
const mobileSidebarContent = document.querySelector(
|
136
|
+
'.cosy\\:h-\\[calc\\(100vh-8rem\\)\\].cosy\\:overflow-y-auto'
|
137
|
+
);
|
138
|
+
|
139
|
+
// 保存移动端滚动位置
|
140
|
+
if (mobileSidebarContent) {
|
141
|
+
localStorage.setItem(
|
142
|
+
'mobileSidebarScrollPosition',
|
143
|
+
mobileSidebarContent.scrollTop.toString()
|
144
|
+
);
|
145
|
+
}
|
146
|
+
});
|
147
|
+
|
148
|
+
document.addEventListener('astro:page-load', () => {
|
149
|
+
// 获取桌面侧边栏滚动容器
|
150
|
+
const desktopSidebarContent = document.querySelector(
|
151
|
+
'aside[data-sidebar] .cosy\\:overflow-y-auto'
|
152
|
+
);
|
153
|
+
|
154
|
+
// 恢复滚动位置
|
155
|
+
if (desktopSidebarContent) {
|
156
|
+
const savedPosition = localStorage.getItem('sidebarScrollPosition');
|
157
|
+
if (savedPosition) {
|
158
|
+
desktopSidebarContent.scrollTop = parseInt(savedPosition, 10);
|
159
|
+
}
|
160
|
+
}
|
161
|
+
|
162
|
+
// 获取移动端侧边栏滚动容器
|
163
|
+
const mobileSidebarContent = document.querySelector(
|
164
|
+
'.cosy\\:h-\\[calc\\(100vh-8rem\\)\\].cosy\\:overflow-y-auto'
|
165
|
+
);
|
166
|
+
|
167
|
+
// 恢复移动端滚动位置
|
168
|
+
if (mobileSidebarContent) {
|
169
|
+
const savedMobilePosition = localStorage.getItem('mobileSidebarScrollPosition');
|
170
|
+
if (savedMobilePosition) {
|
171
|
+
mobileSidebarContent.scrollTop = parseInt(savedMobilePosition, 10);
|
172
|
+
}
|
173
|
+
}
|
174
|
+
});
|
175
|
+
</script>
|
@@ -106,12 +106,11 @@ const {
|
|
106
106
|
maxDepth = 3,
|
107
107
|
containerSelector = 'main',
|
108
108
|
minHeadings = 2,
|
109
|
-
lang: userLang,
|
110
109
|
title,
|
111
110
|
} = Astro.props;
|
112
111
|
|
113
112
|
// 获取当前语言
|
114
|
-
const langInfo = LanguageUtil.getCurrentLanguage(
|
113
|
+
const langInfo = LanguageUtil.getCurrentLanguage(Astro);
|
115
114
|
// 创建文本获取函数
|
116
115
|
const t = createTextGetter(langInfo, 'tableOfContents');
|
117
116
|
// 获取标题文本,如果用户提供了标题则使用用户提供的标题
|
@@ -126,7 +125,8 @@ const tocId = `toc-${Math.random().toString(36).substring(2, 9)}`;
|
|
126
125
|
<div
|
127
126
|
class={`toc-container toc-scroll-container ${fixed ? 'cosy:w-64' : 'cosy:w-full cosy:max-w-xs'}`}
|
128
127
|
id={`${tocId}-container`}
|
129
|
-
style="display: none;"
|
128
|
+
style="display: none;"
|
129
|
+
>
|
130
130
|
<div class="cosy:bg-base-100 cosy:shadow-inner cosy:card">
|
131
131
|
<div class="cosy:p-4 cosy:card-body">
|
132
132
|
<div class="cosy:mb-2 cosy:font-bold cosy:text-lg cosy:card-title">{titleText}</div>
|
package/dist/index.ts
CHANGED
@@ -42,7 +42,7 @@ export { default as Article } from './components/typography/Article.astro';
|
|
42
42
|
export { default as Text } from './components/typography/Text.astro';
|
43
43
|
export { default as Heading } from './components/typography/Heading.astro';
|
44
44
|
|
45
|
-
// Errors Page
|
45
|
+
// Errors Page
|
46
46
|
export { default as ErrorPage404 } from './components/errors/404.astro';
|
47
47
|
|
48
48
|
// Icons
|
@@ -79,6 +79,7 @@ export * from './utils/i18n';
|
|
79
79
|
export * from './utils/path';
|
80
80
|
export * from './utils/url';
|
81
81
|
export * from './utils/language';
|
82
|
+
export * from './utils/lang_package';
|
82
83
|
export * from './utils/logger';
|
83
84
|
export * from './utils/link';
|
84
85
|
|
package/dist/integration.ts
CHANGED
@@ -1,12 +1,12 @@
|
|
1
|
-
import { defineIntegration } from
|
1
|
+
import { defineIntegration } from 'astro-integration-kit';
|
2
2
|
|
3
3
|
export const integration = defineIntegration({
|
4
|
-
name:
|
4
|
+
name: 'cosy-ui',
|
5
5
|
setup() {
|
6
6
|
return {
|
7
7
|
hooks: {
|
8
|
-
|
9
|
-
logger.info(
|
8
|
+
'astro:config:setup': ({ logger }) => {
|
9
|
+
logger.info('cosy-ui integration setup');
|
10
10
|
},
|
11
11
|
},
|
12
12
|
};
|
package/dist/style.ts
CHANGED
@@ -1 +1,2 @@
|
|
1
|
-
|
1
|
+
// 为了让vite处理css文件,所以建立这个文件
|
2
|
+
import './app.css';
|
package/dist/types/footer.ts
CHANGED
@@ -1,143 +1,138 @@
|
|
1
1
|
export interface Logo {
|
2
|
-
|
3
|
-
|
2
|
+
src: string;
|
3
|
+
alt: string;
|
4
4
|
}
|
5
5
|
|
6
6
|
export interface Product {
|
7
|
-
|
8
|
-
|
9
|
-
|
7
|
+
name: string;
|
8
|
+
href: string;
|
9
|
+
external?: boolean;
|
10
10
|
}
|
11
11
|
|
12
12
|
export interface FooterProps {
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
/**
|
140
|
-
* 条款链接
|
141
|
-
*/
|
142
|
-
termsLink?: string;
|
13
|
+
/**
|
14
|
+
* 关于链接
|
15
|
+
*/
|
16
|
+
aboutLink?: string;
|
17
|
+
|
18
|
+
/**
|
19
|
+
* 博客链接
|
20
|
+
*/
|
21
|
+
blogLink?: string;
|
22
|
+
|
23
|
+
/**
|
24
|
+
* 职业链接
|
25
|
+
*/
|
26
|
+
careersLink?: string;
|
27
|
+
|
28
|
+
/**
|
29
|
+
* 公司名称
|
30
|
+
*/
|
31
|
+
company: string;
|
32
|
+
|
33
|
+
/**
|
34
|
+
* 联系链接
|
35
|
+
*/
|
36
|
+
contactLink?: string;
|
37
|
+
|
38
|
+
/**
|
39
|
+
* 版权信息
|
40
|
+
*/
|
41
|
+
copyright: string;
|
42
|
+
|
43
|
+
/**
|
44
|
+
* 调试模式
|
45
|
+
*/
|
46
|
+
debug?: boolean;
|
47
|
+
|
48
|
+
/**
|
49
|
+
* 是否启用日志输出
|
50
|
+
* @default false
|
51
|
+
*/
|
52
|
+
enableLogging?: boolean;
|
53
|
+
|
54
|
+
/**
|
55
|
+
* 常见问题链接
|
56
|
+
*/
|
57
|
+
faqLink?: string;
|
58
|
+
|
59
|
+
/**
|
60
|
+
* 历史链接
|
61
|
+
*/
|
62
|
+
historyLink?: string;
|
63
|
+
|
64
|
+
/**
|
65
|
+
* 首页链接
|
66
|
+
*/
|
67
|
+
homeLink: string;
|
68
|
+
|
69
|
+
/**
|
70
|
+
* ICP备案号
|
71
|
+
*/
|
72
|
+
icp?: string;
|
73
|
+
|
74
|
+
/**
|
75
|
+
* 激励标语
|
76
|
+
*/
|
77
|
+
inspirationalSlogan: string;
|
78
|
+
|
79
|
+
/**
|
80
|
+
* 徽标
|
81
|
+
*/
|
82
|
+
logo?: Logo;
|
83
|
+
|
84
|
+
/**
|
85
|
+
* 媒体链接
|
86
|
+
*/
|
87
|
+
mediaLink?: string;
|
88
|
+
|
89
|
+
/**
|
90
|
+
* 新闻链接
|
91
|
+
*/
|
92
|
+
newsLink?: string;
|
93
|
+
|
94
|
+
/**
|
95
|
+
* 合作伙伴链接
|
96
|
+
*/
|
97
|
+
partnersLink?: string;
|
98
|
+
|
99
|
+
/**
|
100
|
+
* 隐私链接
|
101
|
+
*/
|
102
|
+
privacyLink?: string;
|
103
|
+
|
104
|
+
/**
|
105
|
+
* 产品
|
106
|
+
*/
|
107
|
+
products?: Product[];
|
108
|
+
|
109
|
+
/**
|
110
|
+
* 站点名称
|
111
|
+
*/
|
112
|
+
siteName: string;
|
113
|
+
|
114
|
+
/**
|
115
|
+
* 标语
|
116
|
+
*/
|
117
|
+
slogan: string;
|
118
|
+
|
119
|
+
/**
|
120
|
+
* 社交链接
|
121
|
+
*/
|
122
|
+
socialLinks?: string[];
|
123
|
+
|
124
|
+
/**
|
125
|
+
* 团队链接
|
126
|
+
*/
|
127
|
+
teamLink?: string;
|
128
|
+
|
129
|
+
/**
|
130
|
+
* 技术栈链接
|
131
|
+
*/
|
132
|
+
techStackLink?: string;
|
133
|
+
|
134
|
+
/**
|
135
|
+
* 条款链接
|
136
|
+
*/
|
137
|
+
termsLink?: string;
|
143
138
|
}
|
package/dist/types/header.ts
CHANGED
@@ -1,69 +1,64 @@
|
|
1
1
|
export interface HeaderProps {
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
2
|
+
/**
|
3
|
+
* 侧边栏是否默认展开
|
4
|
+
* @default false
|
5
|
+
*/
|
6
|
+
defaultSidebarOpen?: boolean;
|
6
7
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
/**
|
9
|
+
* 导航栏高度
|
10
|
+
* @default "md"
|
11
|
+
*/
|
12
|
+
height?: '3xs' | '2xs' | 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
height?: '3xs' | '2xs' | 'xs' | 'sm' | 'md' | 'lg' | 'xl';
|
14
|
+
/**
|
15
|
+
* 语言选项列表
|
16
|
+
*/
|
17
|
+
languages?: string[];
|
18
18
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
19
|
+
/**
|
20
|
+
* Logo图片元数据
|
21
|
+
*/
|
22
|
+
logo?: ImageMetadata;
|
23
23
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
24
|
+
/**
|
25
|
+
* Logo 链接地址
|
26
|
+
* @default "/"
|
27
|
+
*/
|
28
|
+
logoHref?: string;
|
28
29
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
logoHref?: string;
|
30
|
+
/**
|
31
|
+
* 导航菜单项
|
32
|
+
*/
|
33
|
+
navItems?: NavItem[];
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
35
|
+
/**
|
36
|
+
* 是否显示侧边栏切换按钮
|
37
|
+
* @default false
|
38
|
+
*/
|
39
|
+
showSidebarToggle?: boolean;
|
39
40
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
41
|
+
/**
|
42
|
+
* 社交链接
|
43
|
+
*/
|
44
|
+
socialLinks?: Array<{
|
45
|
+
name: string;
|
46
|
+
url: string;
|
47
|
+
icon: any;
|
48
|
+
}>;
|
45
49
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
url: string;
|
52
|
-
icon: any;
|
53
|
-
}>;
|
50
|
+
/**
|
51
|
+
* 是否固定在顶部
|
52
|
+
* @default true
|
53
|
+
*/
|
54
|
+
sticky?: boolean;
|
54
55
|
|
55
|
-
|
56
|
-
* 是否固定在顶部
|
57
|
-
* @default true
|
58
|
-
*/
|
59
|
-
sticky?: boolean;
|
56
|
+
rounded?: 'none' | 'sm' | 'md' | 'lg' | 'xl' | 'full';
|
60
57
|
|
61
|
-
|
58
|
+
paddingHorizontal?: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl';
|
59
|
+
paddingVertical?: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl';
|
62
60
|
|
63
|
-
|
64
|
-
paddingVertical?: 'none' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl';
|
65
|
-
|
66
|
-
navPosition?: 'start' | 'center' | 'end';
|
61
|
+
navPosition?: 'start' | 'center' | 'end';
|
67
62
|
}
|
68
63
|
|
69
|
-
export type NavItem = { href: string; label: string
|
64
|
+
export type NavItem = { href: string; label: string };
|
package/dist/utils/i18n.ts
CHANGED
@@ -1,66 +1,64 @@
|
|
1
1
|
/**
|
2
2
|
* 国际化文本配置
|
3
|
-
*
|
3
|
+
*
|
4
4
|
* 提供组件的多语言文本内容
|
5
5
|
*/
|
6
6
|
|
7
|
-
import type { SupportedLanguage, LanguageInfo } from './language';
|
8
|
-
|
9
7
|
// 定义文本内容的类型
|
10
8
|
type TextContent = Record<string, Record<string, string>>;
|
11
9
|
|
12
10
|
// 多语言文本内容
|
13
|
-
export const texts: Record<
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
11
|
+
export const texts: Record<string, TextContent> = {
|
12
|
+
en: {
|
13
|
+
tableOfContents: {
|
14
|
+
title: 'Table of Contents',
|
15
|
+
loading: 'Loading...',
|
16
|
+
},
|
17
|
+
footer: {
|
18
|
+
products: 'Products',
|
19
|
+
about: 'About',
|
20
|
+
aboutUs: 'About Us',
|
21
|
+
team: 'Our Team',
|
22
|
+
careers: 'Careers',
|
23
|
+
contactUs: 'Contact Us',
|
24
|
+
resources: 'Resources',
|
25
|
+
news: 'News',
|
26
|
+
blog: 'Blog',
|
27
|
+
faq: 'FAQ',
|
28
|
+
history: 'History',
|
29
|
+
techStack: 'Tech Stack',
|
30
|
+
legal: 'Legal',
|
31
|
+
terms: 'Terms of Service',
|
32
|
+
privacy: 'Privacy Policy',
|
33
|
+
slogan: 'Build a beautiful digital experience',
|
34
|
+
allRightsReserved: 'All Rights Reserved',
|
35
|
+
},
|
36
|
+
},
|
37
|
+
'zh-cn': {
|
38
|
+
tableOfContents: {
|
39
|
+
title: '目录',
|
40
|
+
loading: '加载中...',
|
41
|
+
},
|
42
|
+
footer: {
|
43
|
+
products: '产品',
|
44
|
+
about: '关于',
|
45
|
+
aboutUs: '关于我们',
|
46
|
+
team: '团队介绍',
|
47
|
+
careers: '加入我们',
|
48
|
+
contactUs: '联系我们',
|
49
|
+
defaultSlogan: '优雅、高效的组件库',
|
50
|
+
resources: '资源',
|
51
|
+
news: '新闻动态',
|
52
|
+
blog: '技术博客',
|
53
|
+
faq: '常见问题',
|
54
|
+
history: '发展历程',
|
55
|
+
techStack: '技术栈',
|
56
|
+
legal: '法律',
|
57
|
+
terms: '服务条款',
|
58
|
+
privacy: '隐私政策',
|
59
|
+
allRightsReserved: '保留所有权利',
|
60
|
+
},
|
61
|
+
},
|
64
62
|
};
|
65
63
|
|
66
64
|
/**
|
@@ -70,8 +68,8 @@ export const texts: Record<SupportedLanguage, TextContent> = {
|
|
70
68
|
* @param key 文本键名
|
71
69
|
* @returns 对应的文本内容
|
72
70
|
*/
|
73
|
-
export function getText(lang:
|
74
|
-
|
71
|
+
export function getText(lang: string, component: string, key: string): string {
|
72
|
+
return texts[lang]?.[component]?.[key] || texts['en'][component]?.[key] || '';
|
75
73
|
}
|
76
74
|
|
77
75
|
/**
|
@@ -80,6 +78,6 @@ export function getText(lang: SupportedLanguage, component: string, key: string)
|
|
80
78
|
* @param component 组件名称
|
81
79
|
* @returns 文本获取函数
|
82
80
|
*/
|
83
|
-
export function createTextGetter(langInfo:
|
84
|
-
|
85
|
-
}
|
81
|
+
export function createTextGetter(langInfo: string, component: string) {
|
82
|
+
return (key: string): string => getText(langInfo, component, key);
|
83
|
+
}
|
@@ -0,0 +1,222 @@
|
|
1
|
+
/**
|
2
|
+
* 多语言工具类
|
3
|
+
* 提供链式API来创建和管理多语言文本
|
4
|
+
*/
|
5
|
+
export class LangEntry {
|
6
|
+
private translations: Record<string, string> = {};
|
7
|
+
|
8
|
+
/**
|
9
|
+
* 设置中文文本
|
10
|
+
* @param text 中文文本
|
11
|
+
*/
|
12
|
+
setZh(text: string): LangEntry {
|
13
|
+
this.translations['zh-cn'] = text;
|
14
|
+
return this;
|
15
|
+
}
|
16
|
+
|
17
|
+
/**
|
18
|
+
* 设置英文文本
|
19
|
+
* @param text 英文文本
|
20
|
+
*/
|
21
|
+
setEn(text: string): LangEntry {
|
22
|
+
this.translations['en'] = text;
|
23
|
+
return this;
|
24
|
+
}
|
25
|
+
|
26
|
+
/**
|
27
|
+
* 设置日文文本
|
28
|
+
* @param text 日文文本
|
29
|
+
*/
|
30
|
+
setJa(text: string): LangEntry {
|
31
|
+
this.translations['ja'] = text;
|
32
|
+
return this;
|
33
|
+
}
|
34
|
+
|
35
|
+
/**
|
36
|
+
* 设置任意语言的文本
|
37
|
+
* @param lang 语言代码
|
38
|
+
* @param text 文本内容
|
39
|
+
*/
|
40
|
+
set(lang: string, text: string): LangEntry {
|
41
|
+
this.translations[lang] = text;
|
42
|
+
return this;
|
43
|
+
}
|
44
|
+
|
45
|
+
/**
|
46
|
+
* 设置所有语言为相同的文本值
|
47
|
+
* 适用于不需要翻译的品牌名、专有名词等
|
48
|
+
* @param text 所有语言共用的文本
|
49
|
+
*/
|
50
|
+
setAll(text: string): LangEntry {
|
51
|
+
// 如果已有语言,则更新它们
|
52
|
+
if (Object.keys(this.translations).length > 0) {
|
53
|
+
for (const lang of Object.keys(this.translations)) {
|
54
|
+
this.translations[lang] = text;
|
55
|
+
}
|
56
|
+
} else {
|
57
|
+
// 默认至少设置中英文
|
58
|
+
this.translations['zh-cn'] = text;
|
59
|
+
this.translations['en'] = text;
|
60
|
+
}
|
61
|
+
return this;
|
62
|
+
}
|
63
|
+
|
64
|
+
/**
|
65
|
+
* 获取指定语言的文本
|
66
|
+
* @param lang 语言代码
|
67
|
+
* @param defaultValue 默认值,如果未找到翻译则返回此值
|
68
|
+
*/
|
69
|
+
get(lang: string, defaultValue?: string): string {
|
70
|
+
return this.translations[lang] || defaultValue || this.getFirst() || '';
|
71
|
+
}
|
72
|
+
|
73
|
+
/**
|
74
|
+
* 获取第一个可用的翻译文本
|
75
|
+
*/
|
76
|
+
getFirst(): string | undefined {
|
77
|
+
const keys = Object.keys(this.translations);
|
78
|
+
return keys.length > 0 ? this.translations[keys[0]] : undefined;
|
79
|
+
}
|
80
|
+
|
81
|
+
/**
|
82
|
+
* 获取所有可用的语言代码
|
83
|
+
*/
|
84
|
+
getLanguages(): string[] {
|
85
|
+
return Object.keys(this.translations);
|
86
|
+
}
|
87
|
+
|
88
|
+
/**
|
89
|
+
* 获取所有翻译
|
90
|
+
*/
|
91
|
+
getAll(): Record<string, string> {
|
92
|
+
return { ...this.translations };
|
93
|
+
}
|
94
|
+
|
95
|
+
/**
|
96
|
+
* 合并另一个语言条目
|
97
|
+
* @param other 要合并的语言条目
|
98
|
+
*/
|
99
|
+
merge(other: LangEntry): LangEntry {
|
100
|
+
Object.assign(this.translations, other.getAll());
|
101
|
+
return this;
|
102
|
+
}
|
103
|
+
|
104
|
+
/**
|
105
|
+
* 检查是否包含指定语言
|
106
|
+
* @param lang 语言代码
|
107
|
+
*/
|
108
|
+
has(lang: string): boolean {
|
109
|
+
return lang in this.translations;
|
110
|
+
}
|
111
|
+
|
112
|
+
/**
|
113
|
+
* 转换为普通对象
|
114
|
+
*/
|
115
|
+
toObject(): Record<string, string> {
|
116
|
+
return { ...this.translations };
|
117
|
+
}
|
118
|
+
|
119
|
+
/**
|
120
|
+
* 允许以对象属性方式访问翻译
|
121
|
+
* 例如: entry['zh-cn'] 或 entry.en
|
122
|
+
*/
|
123
|
+
[key: string]: any;
|
124
|
+
}
|
125
|
+
|
126
|
+
// 创建索引访问器的Proxy处理程序
|
127
|
+
const langEntryHandler: ProxyHandler<LangEntry> = {
|
128
|
+
get(target: LangEntry, prop: string | symbol): any {
|
129
|
+
// 如果是字符串属性并且不是LangEntry的方法,则尝试作为语言代码获取翻译
|
130
|
+
if (typeof prop === 'string' &&
|
131
|
+
!(prop in Object.getPrototypeOf(target)) &&
|
132
|
+
prop !== 'translations') {
|
133
|
+
return target.get(prop);
|
134
|
+
}
|
135
|
+
|
136
|
+
// 否则返回原始属性
|
137
|
+
return (target as any)[prop];
|
138
|
+
}
|
139
|
+
};
|
140
|
+
|
141
|
+
/**
|
142
|
+
* 提供快捷访问的LangPackage
|
143
|
+
* 可以直接通过静态方法创建和配置语言条目
|
144
|
+
*/
|
145
|
+
export class LangPackage {
|
146
|
+
// 内部实例,用于静态方法直接操作
|
147
|
+
private static _instance = new Proxy(new LangEntry(), langEntryHandler);
|
148
|
+
|
149
|
+
/**
|
150
|
+
* 创建一个新的语言条目
|
151
|
+
*/
|
152
|
+
static make(): LangEntry {
|
153
|
+
return new Proxy(new LangEntry(), langEntryHandler);
|
154
|
+
}
|
155
|
+
|
156
|
+
/**
|
157
|
+
* 从对象创建语言条目
|
158
|
+
* @param obj 包含语言翻译的对象
|
159
|
+
*/
|
160
|
+
static from(obj: Record<string, string>): LangEntry {
|
161
|
+
const entry = new LangEntry();
|
162
|
+
Object.entries(obj).forEach(([lang, text]) => {
|
163
|
+
entry.set(lang, text);
|
164
|
+
});
|
165
|
+
return new Proxy(entry, langEntryHandler);
|
166
|
+
}
|
167
|
+
|
168
|
+
/**
|
169
|
+
* 创建只包含中文和英文的语言条目
|
170
|
+
* @param zh 中文文本
|
171
|
+
* @param en 英文文本
|
172
|
+
*/
|
173
|
+
static zhEn(zh: string, en: string): LangEntry {
|
174
|
+
return new Proxy(new LangEntry().setZh(zh).setEn(en), langEntryHandler);
|
175
|
+
}
|
176
|
+
|
177
|
+
/**
|
178
|
+
* 创建所有语言都使用相同文本的语言条目
|
179
|
+
* 适用于品牌名、产品名等不需要翻译的文本
|
180
|
+
* @param text 所有语言共用的文本
|
181
|
+
*/
|
182
|
+
static common(text: string): LangEntry {
|
183
|
+
return new Proxy(new LangEntry().setAll(text), langEntryHandler);
|
184
|
+
}
|
185
|
+
|
186
|
+
/**
|
187
|
+
* 设置中文文本
|
188
|
+
* 快捷方法,直接返回一个新的LangEntry实例
|
189
|
+
* @param text 中文文本
|
190
|
+
*/
|
191
|
+
static setZh(text: string): LangEntry {
|
192
|
+
return new Proxy(new LangEntry().setZh(text), langEntryHandler);
|
193
|
+
}
|
194
|
+
|
195
|
+
/**
|
196
|
+
* 设置英文文本
|
197
|
+
* 快捷方法,直接返回一个新的LangEntry实例
|
198
|
+
* @param text 英文文本
|
199
|
+
*/
|
200
|
+
static setEn(text: string): LangEntry {
|
201
|
+
return new Proxy(new LangEntry().setEn(text), langEntryHandler);
|
202
|
+
}
|
203
|
+
|
204
|
+
/**
|
205
|
+
* 设置日文文本
|
206
|
+
* 快捷方法,直接返回一个新的LangEntry实例
|
207
|
+
* @param text 日文文本
|
208
|
+
*/
|
209
|
+
static setJa(text: string): LangEntry {
|
210
|
+
return new Proxy(new LangEntry().setJa(text), langEntryHandler);
|
211
|
+
}
|
212
|
+
|
213
|
+
/**
|
214
|
+
* 设置任意语言的文本
|
215
|
+
* 快捷方法,直接返回一个新的LangEntry实例
|
216
|
+
* @param lang 语言代码
|
217
|
+
* @param text 文本内容
|
218
|
+
*/
|
219
|
+
static set(lang: string, text: string): LangEntry {
|
220
|
+
return new Proxy(new LangEntry().set(lang, text), langEntryHandler);
|
221
|
+
}
|
222
|
+
}
|
package/dist/utils/language.ts
CHANGED
@@ -1,175 +1,126 @@
|
|
1
1
|
/**
|
2
2
|
* 语言工具模块
|
3
|
-
*
|
3
|
+
*
|
4
4
|
* 提供语言相关的工具函数,用于多语言支持
|
5
5
|
*/
|
6
6
|
|
7
7
|
import { getRelativeLocaleUrl } from 'astro:i18n';
|
8
8
|
import { logger } from './logger';
|
9
|
-
import { LinkUtil } from './link';
|
10
9
|
import type { AstroGlobal } from 'astro';
|
11
10
|
|
12
|
-
// 支持的语言列表
|
13
|
-
export const SUPPORTED_LANGUAGES = ['en', 'zh-cn', 'zh'] as const;
|
14
|
-
export type SupportedLanguage = typeof SUPPORTED_LANGUAGES[number];
|
15
|
-
|
16
11
|
// 默认语言
|
17
|
-
export const DEFAULT_LANGUAGE
|
12
|
+
export const DEFAULT_LANGUAGE = 'en';
|
18
13
|
|
19
14
|
export class LanguageUtil {
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
return undefined;
|
132
|
-
}
|
133
|
-
/**
|
134
|
-
* 获取当前语言
|
135
|
-
* @param userLang 用户指定的语言(可选)
|
136
|
-
* @param url 当前URL(可选)
|
137
|
-
* @returns 当前应使用的语言信息,包括语言代码和来源
|
138
|
-
*/
|
139
|
-
static getCurrentLanguage(userLang?: string, url?: string): string {
|
140
|
-
// 如果用户指定了语言,优先使用用户指定的语言
|
141
|
-
if (userLang) {
|
142
|
-
if (this.isLanguageSupported(userLang)) {
|
143
|
-
return userLang as SupportedLanguage;
|
144
|
-
} else {
|
145
|
-
// 用户指定的语言不支持,使用默认语言
|
146
|
-
return DEFAULT_LANGUAGE;
|
147
|
-
}
|
148
|
-
}
|
149
|
-
|
150
|
-
// 否则自动检测语言
|
151
|
-
return this.detectLanguage();
|
152
|
-
}
|
153
|
-
|
154
|
-
/**
|
155
|
-
* 自动检测当前语言
|
156
|
-
* @param url 当前URL(可选)
|
157
|
-
* @returns 检测到的语言信息,包括语言代码和来源
|
158
|
-
*/
|
159
|
-
static detectLanguage(url?: string): string {
|
160
|
-
// 尝试从URL中获取语言
|
161
|
-
const urlLang = this.getLanguageFromURL(url);
|
162
|
-
if (urlLang) {
|
163
|
-
return urlLang as SupportedLanguage;
|
164
|
-
}
|
165
|
-
|
166
|
-
// 尝试从浏览器设置中获取语言
|
167
|
-
const browserLang = this.getLanguageFromBrowser();
|
168
|
-
if (browserLang) {
|
169
|
-
return browserLang as SupportedLanguage;
|
170
|
-
}
|
171
|
-
|
172
|
-
// 如果无法检测,返回默认语言
|
173
|
-
return DEFAULT_LANGUAGE;
|
174
|
-
}
|
15
|
+
static getRelativeLink(locale: string, astro: AstroGlobal): string {
|
16
|
+
const debug = false;
|
17
|
+
const currentLocale = astro.currentLocale;
|
18
|
+
const originalPath = astro.originPathname;
|
19
|
+
const result = getRelativeLocaleUrl(locale, originalPath.replaceAll('/' + currentLocale, ''));
|
20
|
+
|
21
|
+
if (debug) {
|
22
|
+
logger.debug(
|
23
|
+
`getRelativeLink: locale=${locale}, currentPath=${originalPath}, currentLocale=${currentLocale}, result=${result}`
|
24
|
+
);
|
25
|
+
}
|
26
|
+
|
27
|
+
return result;
|
28
|
+
}
|
29
|
+
|
30
|
+
static getLanguageName(code: string | undefined): string {
|
31
|
+
switch (code) {
|
32
|
+
case 'en':
|
33
|
+
return 'English';
|
34
|
+
case 'zh-cn':
|
35
|
+
return '简体中文';
|
36
|
+
case 'zh':
|
37
|
+
return '中文';
|
38
|
+
case undefined:
|
39
|
+
default:
|
40
|
+
return 'not known';
|
41
|
+
}
|
42
|
+
}
|
43
|
+
|
44
|
+
/**
|
45
|
+
* 获取当前语言
|
46
|
+
* @param astro Astro全局对象
|
47
|
+
* @returns 当前应使用的语言代码
|
48
|
+
*/
|
49
|
+
static getCurrentLanguage(astro: AstroGlobal): string {
|
50
|
+
// 尝试从Astro全局对象中获取语言
|
51
|
+
const astroLang = astro.currentLocale;
|
52
|
+
if (astroLang) {
|
53
|
+
return astroLang;
|
54
|
+
}
|
55
|
+
// 尝试从URL中获取语言
|
56
|
+
const urlLang = this.getLanguageFromURL(astro.url.pathname);
|
57
|
+
if (urlLang) {
|
58
|
+
return urlLang;
|
59
|
+
}
|
60
|
+
|
61
|
+
// 尝试从浏览器设置中获取语言
|
62
|
+
const browserLang = this.getLanguageFromBrowser();
|
63
|
+
if (browserLang) {
|
64
|
+
return browserLang;
|
65
|
+
}
|
66
|
+
|
67
|
+
// 尝试从Astro全局对象中获取语言
|
68
|
+
const preferredLocale = astro.preferredLocale;
|
69
|
+
if (preferredLocale) {
|
70
|
+
return preferredLocale;
|
71
|
+
}
|
72
|
+
|
73
|
+
// 如果无法检测,返回默认语言
|
74
|
+
return DEFAULT_LANGUAGE;
|
75
|
+
}
|
76
|
+
|
77
|
+
/**
|
78
|
+
* 从URL中提取语言代码
|
79
|
+
* @param url 当前URL
|
80
|
+
* @returns 从URL中提取的语言代码,如果无法提取则返回undefined
|
81
|
+
*/
|
82
|
+
private static getLanguageFromURL(url: string): string | undefined {
|
83
|
+
let currentUrl = url;
|
84
|
+
|
85
|
+
if (currentUrl === undefined) {
|
86
|
+
if (typeof window === 'undefined') return undefined;
|
87
|
+
currentUrl = window.location.href;
|
88
|
+
}
|
89
|
+
|
90
|
+
// 尝试从路径中提取语言代码
|
91
|
+
// 例如: /zh-cn/components/button
|
92
|
+
const pathMatch = currentUrl.match(/^\/([\w-]+)\//);
|
93
|
+
if (pathMatch) {
|
94
|
+
return pathMatch[1];
|
95
|
+
}
|
96
|
+
|
97
|
+
// 如果网站运行在二级目录,则从路径中提取语言代码
|
98
|
+
// 例如: /docs/zh-cn/components/button
|
99
|
+
const pathMatch2 = currentUrl.match(/^\/([^\/]+)\/([\w-]+)\//);
|
100
|
+
if (pathMatch2) {
|
101
|
+
return pathMatch2[2];
|
102
|
+
}
|
103
|
+
|
104
|
+
// 尝试从查询参数中提取语言代码
|
105
|
+
// 例如: ?lang=zh-cn
|
106
|
+
const urlParams = new URLSearchParams(currentUrl.split('?')[1]);
|
107
|
+
const langParam = urlParams.get('lang');
|
108
|
+
if (langParam) {
|
109
|
+
return langParam;
|
110
|
+
}
|
111
|
+
|
112
|
+
return undefined;
|
113
|
+
}
|
114
|
+
|
115
|
+
/**
|
116
|
+
* 从浏览器设置中获取首选语言
|
117
|
+
* @returns 从浏览器设置中获取的语言代码,如果无法获取则返回undefined
|
118
|
+
*/
|
119
|
+
private static getLanguageFromBrowser(): string | undefined {
|
120
|
+
if (typeof navigator === 'undefined') return undefined;
|
121
|
+
|
122
|
+
// 获取浏览器语言
|
123
|
+
const browserLang = navigator.language.toLowerCase();
|
124
|
+
return browserLang;
|
125
|
+
}
|
175
126
|
}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@coffic/cosy-ui",
|
3
|
-
"version": "0.5.
|
3
|
+
"version": "0.5.8",
|
4
4
|
"description": "An astro component library",
|
5
5
|
"author": {
|
6
6
|
"name": "nookery",
|
@@ -31,7 +31,7 @@
|
|
31
31
|
"index.ts"
|
32
32
|
],
|
33
33
|
"scripts": {
|
34
|
-
"dev": "astro dev --host 0.0.0.0 --port
|
34
|
+
"dev": "astro dev --host 0.0.0.0 --port 6677",
|
35
35
|
"preview:docs": "astro preview --host 0.0.0.0 --port 4330 --outDir dist-docs",
|
36
36
|
"preview": "npm run preview:docs",
|
37
37
|
"build": "vite build && npm run build:docs && tsx scripts/post-build.ts",
|