@jet-w/astro-blog 0.2.4 → 0.2.5
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/{chunk-Z3O3JK56.js → chunk-CEZBWSMU.js} +34 -5
- package/dist/index.js +1 -1
- package/dist/utils/i18n.d.ts +34 -2
- package/dist/utils/i18n.js +6 -2
- package/package.json +1 -1
- package/src/components/blog/Hero.astro +8 -4
- package/src/components/blog/PostCard.astro +8 -4
- package/src/components/home/FeaturedPostsSection.astro +2 -1
- package/src/components/home/QuickNavSection.astro +2 -1
- package/src/components/home/RecentPostsSection.astro +2 -1
- package/src/components/layout/Footer.astro +2 -1
- package/src/components/layout/Header.astro +8 -4
- package/src/components/layout/Sidebar.astro +2 -1
- package/src/layouts/BaseLayout.astro +8 -4
- package/src/pages/archives/[year]/[month].astro +2 -1
- package/src/pages/archives/index.astro +2 -1
- package/src/pages/categories/[category].astro +2 -1
- package/src/pages/categories/index.astro +2 -1
- package/src/pages/posts/[...slug].astro +2 -1
- package/src/pages/posts/index.astro +2 -1
- package/src/pages/posts/page/[page].astro +2 -1
- package/src/pages/slides/index.astro +2 -1
- package/src/pages/tags/[tag].astro +2 -1
- package/src/pages/tags/index.astro +2 -1
- package/src/utils/i18n.ts +83 -4
- package/templates/default/.claude/ralph-loop.local.md +34 -43
- package/templates/default/astro.config.mjs +2 -2
- package/templates/default/package-lock.json +0 -9667
- package/templates/default/package.dev.json +0 -31
|
@@ -145,11 +145,16 @@ function getTextDirection(locale, config = defaultI18nConfig) {
|
|
|
145
145
|
function isMultiLanguageEnabled(config = defaultI18nConfig) {
|
|
146
146
|
return config.locales.length > 1;
|
|
147
147
|
}
|
|
148
|
-
function getLocalePrefix(locale, config = defaultI18nConfig) {
|
|
149
|
-
|
|
150
|
-
|
|
148
|
+
function getLocalePrefix(locale, config = defaultI18nConfig, base) {
|
|
149
|
+
const normalizedBase = base ? base.replace(/\/$/, "") : "";
|
|
150
|
+
let localePrefix = "";
|
|
151
|
+
if (locale !== config.defaultLocale || config.routing.prefixDefaultLocale) {
|
|
152
|
+
localePrefix = `/${locale}`;
|
|
153
|
+
}
|
|
154
|
+
if (!normalizedBase || normalizedBase === "") {
|
|
155
|
+
return localePrefix;
|
|
151
156
|
}
|
|
152
|
-
return
|
|
157
|
+
return `${normalizedBase}${localePrefix}`;
|
|
153
158
|
}
|
|
154
159
|
function getContentPathPrefix(locale, config = defaultI18nConfig) {
|
|
155
160
|
const localeConfig = config.localeConfigs[locale];
|
|
@@ -166,6 +171,28 @@ function filterPostsByLocale(posts, locale, config = defaultI18nConfig) {
|
|
|
166
171
|
return postPath.startsWith(prefix + "/") || postPath === prefix;
|
|
167
172
|
});
|
|
168
173
|
}
|
|
174
|
+
function withBase(path, base) {
|
|
175
|
+
const baseUrl = (base || "/").replace(/\/$/, "");
|
|
176
|
+
if (!baseUrl || baseUrl === "") {
|
|
177
|
+
return path;
|
|
178
|
+
}
|
|
179
|
+
const normalizedPath = path.startsWith("/") ? path : `/${path}`;
|
|
180
|
+
if (normalizedPath === "/") {
|
|
181
|
+
return `${baseUrl}/`;
|
|
182
|
+
}
|
|
183
|
+
return `${baseUrl}${normalizedPath}`;
|
|
184
|
+
}
|
|
185
|
+
function removeBase(path, base) {
|
|
186
|
+
const baseUrl = (base || "/").replace(/\/$/, "");
|
|
187
|
+
if (!baseUrl || baseUrl === "") {
|
|
188
|
+
return path;
|
|
189
|
+
}
|
|
190
|
+
if (path.startsWith(baseUrl)) {
|
|
191
|
+
const rest = path.slice(baseUrl.length);
|
|
192
|
+
return rest || "/";
|
|
193
|
+
}
|
|
194
|
+
return path;
|
|
195
|
+
}
|
|
169
196
|
|
|
170
197
|
export {
|
|
171
198
|
getLocaleFromPath,
|
|
@@ -182,5 +209,7 @@ export {
|
|
|
182
209
|
isMultiLanguageEnabled,
|
|
183
210
|
getLocalePrefix,
|
|
184
211
|
getContentPathPrefix,
|
|
185
|
-
filterPostsByLocale
|
|
212
|
+
filterPostsByLocale,
|
|
213
|
+
withBase,
|
|
214
|
+
removeBase
|
|
186
215
|
};
|
package/dist/index.js
CHANGED
package/dist/utils/i18n.d.ts
CHANGED
|
@@ -109,8 +109,18 @@ declare function isMultiLanguageEnabled(config?: I18nConfig): boolean;
|
|
|
109
109
|
/**
|
|
110
110
|
* Get prefix for a locale in routes
|
|
111
111
|
* Returns empty string for default locale if prefixDefaultLocale is false
|
|
112
|
+
* If base is provided, it will be prepended to the locale prefix
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* // Without base
|
|
116
|
+
* getLocalePrefix('en', config) // '' (for default locale)
|
|
117
|
+
* getLocalePrefix('zh-CN', config) // '/zh-CN'
|
|
118
|
+
*
|
|
119
|
+
* // With base '/my-blog'
|
|
120
|
+
* getLocalePrefix('en', config, '/my-blog') // '/my-blog'
|
|
121
|
+
* getLocalePrefix('zh-CN', config, '/my-blog') // '/my-blog/zh-CN'
|
|
112
122
|
*/
|
|
113
|
-
declare function getLocalePrefix(locale: string, config?: I18nConfig): string;
|
|
123
|
+
declare function getLocalePrefix(locale: string, config?: I18nConfig, base?: string): string;
|
|
114
124
|
/**
|
|
115
125
|
* Get content path prefix for a specific locale
|
|
116
126
|
* Returns the contentPathPrefix from locale config, or undefined if not set
|
|
@@ -129,5 +139,27 @@ declare function getContentPathPrefix(locale: string, config?: I18nConfig): stri
|
|
|
129
139
|
declare function filterPostsByLocale<T extends {
|
|
130
140
|
id: string;
|
|
131
141
|
}>(posts: T[], locale: string, config?: I18nConfig): T[];
|
|
142
|
+
/**
|
|
143
|
+
* Add base URL prefix to a path
|
|
144
|
+
* This is used when the site is deployed to a subdirectory (e.g., /jet-w.astro-blog/)
|
|
145
|
+
*
|
|
146
|
+
* @example
|
|
147
|
+
* // If BASE_URL is '/jet-w.astro-blog'
|
|
148
|
+
* withBase('/posts') // '/jet-w.astro-blog/posts'
|
|
149
|
+
* withBase('/') // '/jet-w.astro-blog/'
|
|
150
|
+
*
|
|
151
|
+
* // If BASE_URL is '/'
|
|
152
|
+
* withBase('/posts') // '/posts'
|
|
153
|
+
*/
|
|
154
|
+
declare function withBase(path: string, base?: string): string;
|
|
155
|
+
/**
|
|
156
|
+
* Remove base URL prefix from a path
|
|
157
|
+
* Useful for getting the actual path without base prefix
|
|
158
|
+
*
|
|
159
|
+
* @example
|
|
160
|
+
* // If BASE_URL is '/jet-w.astro-blog'
|
|
161
|
+
* removeBase('/jet-w.astro-blog/posts', '/jet-w.astro-blog') // '/posts'
|
|
162
|
+
*/
|
|
163
|
+
declare function removeBase(path: string, base?: string): string;
|
|
132
164
|
|
|
133
|
-
export { type AlternateLink, I18nConfig, Locale, type MergedLocaleConfig, UITranslations, filterPostsByLocale, formatDate, formatDateShort, getAlternateLinks, getContentPathPrefix, getLocaleByCode, getLocaleConfig, getLocaleFromPath, getLocalePrefix, getLocalizedPath, getTextDirection, isMultiLanguageEnabled, isRTL, removeLocalePrefix, t };
|
|
165
|
+
export { type AlternateLink, I18nConfig, Locale, type MergedLocaleConfig, UITranslations, filterPostsByLocale, formatDate, formatDateShort, getAlternateLinks, getContentPathPrefix, getLocaleByCode, getLocaleConfig, getLocaleFromPath, getLocalePrefix, getLocalizedPath, getTextDirection, isMultiLanguageEnabled, isRTL, removeBase, removeLocalePrefix, t, withBase };
|
package/dist/utils/i18n.js
CHANGED
|
@@ -12,9 +12,11 @@ import {
|
|
|
12
12
|
getTextDirection,
|
|
13
13
|
isMultiLanguageEnabled,
|
|
14
14
|
isRTL,
|
|
15
|
+
removeBase,
|
|
15
16
|
removeLocalePrefix,
|
|
16
|
-
t
|
|
17
|
-
|
|
17
|
+
t,
|
|
18
|
+
withBase
|
|
19
|
+
} from "../chunk-CEZBWSMU.js";
|
|
18
20
|
import "../chunk-DAH2XP4W.js";
|
|
19
21
|
import {
|
|
20
22
|
builtInTranslations,
|
|
@@ -43,7 +45,9 @@ export {
|
|
|
43
45
|
getUITranslations,
|
|
44
46
|
isMultiLanguageEnabled,
|
|
45
47
|
isRTL,
|
|
48
|
+
removeBase,
|
|
46
49
|
removeLocalePrefix,
|
|
47
50
|
t,
|
|
51
|
+
withBase,
|
|
48
52
|
zhCNTranslations
|
|
49
53
|
};
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@ import { siteConfig } from '@jet-w/astro-blog/config';
|
|
|
3
3
|
import type { I18nConfig } from '../../config/i18n';
|
|
4
4
|
import { defaultI18nConfig } from '../../config/i18n';
|
|
5
5
|
import { i18nConfig as virtualI18nConfig } from 'virtual:astro-blog-i18n';
|
|
6
|
-
import { getLocaleFromPath, getLocaleConfig } from '../../utils/i18n';
|
|
6
|
+
import { getLocaleFromPath, getLocaleConfig, getLocalePrefix, withBase } from '../../utils/i18n';
|
|
7
7
|
|
|
8
8
|
export interface Props {
|
|
9
9
|
i18nConfig?: I18nConfig;
|
|
@@ -15,6 +15,10 @@ const { i18nConfig = virtualI18nConfig || defaultI18nConfig } = Astro.props;
|
|
|
15
15
|
const currentLocale = getLocaleFromPath(Astro.url.pathname, i18nConfig);
|
|
16
16
|
const localeConfig = getLocaleConfig(currentLocale, i18nConfig);
|
|
17
17
|
const ui = localeConfig.ui;
|
|
18
|
+
|
|
19
|
+
// Get base URL for prefixing links
|
|
20
|
+
const base = import.meta.env.BASE_URL;
|
|
21
|
+
const localePrefix = getLocalePrefix(currentLocale, i18nConfig, base);
|
|
18
22
|
---
|
|
19
23
|
|
|
20
24
|
<section class="py-16 mb-16">
|
|
@@ -23,7 +27,7 @@ const ui = localeConfig.ui;
|
|
|
23
27
|
{siteConfig.avatar && (
|
|
24
28
|
<div class="mb-8">
|
|
25
29
|
<img
|
|
26
|
-
src={siteConfig.avatar}
|
|
30
|
+
src={withBase(siteConfig.avatar, base)}
|
|
27
31
|
alt={siteConfig.author}
|
|
28
32
|
class="w-32 h-32 rounded-full mx-auto shadow-lg"
|
|
29
33
|
/>
|
|
@@ -101,7 +105,7 @@ const ui = localeConfig.ui;
|
|
|
101
105
|
<!-- 行动按钮 -->
|
|
102
106
|
<div class="flex flex-col sm:flex-row gap-4 justify-center">
|
|
103
107
|
<a
|
|
104
|
-
href=
|
|
108
|
+
href={`${localePrefix}/posts`}
|
|
105
109
|
class="btn-primary inline-flex items-center space-x-2"
|
|
106
110
|
>
|
|
107
111
|
<span>{ui.browsePosts}</span>
|
|
@@ -111,7 +115,7 @@ const ui = localeConfig.ui;
|
|
|
111
115
|
</a>
|
|
112
116
|
|
|
113
117
|
<a
|
|
114
|
-
href=
|
|
118
|
+
href={`${localePrefix}/about`}
|
|
115
119
|
class="btn-secondary inline-flex items-center space-x-2"
|
|
116
120
|
>
|
|
117
121
|
<span>{ui.aboutMe}</span>
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
---
|
|
2
|
+
import { withBase } from '../../utils/i18n';
|
|
3
|
+
|
|
2
4
|
export interface Props {
|
|
3
5
|
post: {
|
|
4
6
|
slug: string;
|
|
@@ -30,6 +32,8 @@ const {
|
|
|
30
32
|
ui = { readMore: '阅读更多', minuteRead: '分钟' }
|
|
31
33
|
} = Astro.props;
|
|
32
34
|
|
|
35
|
+
const base = import.meta.env.BASE_URL;
|
|
36
|
+
|
|
33
37
|
const formattedDate = post.pubDate
|
|
34
38
|
? new Intl.DateTimeFormat(locale, {
|
|
35
39
|
year: 'numeric',
|
|
@@ -45,10 +49,10 @@ const tagToSlug = (tag: string) => tag.toLowerCase().replace(/\s+/g, '-');
|
|
|
45
49
|
// 将分类名转换为 slug 格式
|
|
46
50
|
const categoryToSlug = (category: string) => category.toLowerCase().replace(/\s+/g, '-');
|
|
47
51
|
|
|
48
|
-
// Build URLs with locale prefix
|
|
49
|
-
const postUrl = `${localePrefix}/posts/${post.slug}
|
|
50
|
-
const tagUrl = (tag: string) => `${localePrefix}/tags/${tagToSlug(tag)}
|
|
51
|
-
const categoryUrl = (category: string) => `${localePrefix}/categories/${categoryToSlug(category)}
|
|
52
|
+
// Build URLs with locale prefix and base URL
|
|
53
|
+
const postUrl = withBase(`${localePrefix}/posts/${post.slug}`, base);
|
|
54
|
+
const tagUrl = (tag: string) => withBase(`${localePrefix}/tags/${tagToSlug(tag)}`, base);
|
|
55
|
+
const categoryUrl = (category: string) => withBase(`${localePrefix}/categories/${categoryToSlug(category)}`, base);
|
|
52
56
|
---
|
|
53
57
|
|
|
54
58
|
<article class={`group card hover:shadow-lg transform hover:-translate-y-1 transition-all duration-300 ${isHorizontal ? 'flex gap-6 items-center' : 'block'}`}>
|
|
@@ -20,7 +20,8 @@ const { count = 3, i18nConfig = virtualI18nConfig || defaultI18nConfig } = Astro
|
|
|
20
20
|
const currentLocale = getLocaleFromPath(Astro.url.pathname, i18nConfig);
|
|
21
21
|
const localeConfig = getLocaleConfig(currentLocale, i18nConfig);
|
|
22
22
|
const ui = localeConfig.ui;
|
|
23
|
-
const
|
|
23
|
+
const base = import.meta.env.BASE_URL;
|
|
24
|
+
const localePrefix = getLocalePrefix(currentLocale, i18nConfig, base);
|
|
24
25
|
|
|
25
26
|
const allPosts = await getCollection('posts');
|
|
26
27
|
const publishedPosts = allPosts
|
|
@@ -19,7 +19,8 @@ const { i18nConfig = virtualI18nConfig || defaultI18nConfig } = Astro.props;
|
|
|
19
19
|
const currentLocale = getLocaleFromPath(Astro.url.pathname, i18nConfig);
|
|
20
20
|
const localeConfig = getLocaleConfig(currentLocale, i18nConfig);
|
|
21
21
|
const ui = localeConfig.ui;
|
|
22
|
-
const
|
|
22
|
+
const base = import.meta.env.BASE_URL;
|
|
23
|
+
const localePrefix = getLocalePrefix(currentLocale, i18nConfig, base);
|
|
23
24
|
|
|
24
25
|
const allPosts = await getCollection('posts', ({ data }) => !data.draft);
|
|
25
26
|
|
|
@@ -20,7 +20,8 @@ const { count = 6, i18nConfig = virtualI18nConfig || defaultI18nConfig } = Astro
|
|
|
20
20
|
const currentLocale = getLocaleFromPath(Astro.url.pathname, i18nConfig);
|
|
21
21
|
const localeConfig = getLocaleConfig(currentLocale, i18nConfig);
|
|
22
22
|
const ui = localeConfig.ui;
|
|
23
|
-
const
|
|
23
|
+
const base = import.meta.env.BASE_URL;
|
|
24
|
+
const localePrefix = getLocalePrefix(currentLocale, i18nConfig, base);
|
|
24
25
|
|
|
25
26
|
const allPosts = await getCollection('posts');
|
|
26
27
|
const publishedPosts = allPosts
|
|
@@ -25,7 +25,8 @@ function getIcon(link: { type: string; icon?: string }): string {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
// Get locale prefix for RSS link
|
|
28
|
-
const
|
|
28
|
+
const base = import.meta.env.BASE_URL;
|
|
29
|
+
const localePrefix = getLocalePrefix(currentLocale, i18nConfig, base);
|
|
29
30
|
const rssUrl = localeFooterConfig.rssUrl || footerConfig.rssUrl || `${localePrefix}/rss.xml`;
|
|
30
31
|
|
|
31
32
|
const copyright = (localeFooterConfig.copyright || footerConfig.copyright)
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
getLocaleConfig,
|
|
13
13
|
removeLocalePrefix,
|
|
14
14
|
isMultiLanguageEnabled,
|
|
15
|
+
withBase,
|
|
15
16
|
} from '../../utils/i18n';
|
|
16
17
|
|
|
17
18
|
export interface Props {
|
|
@@ -40,16 +41,19 @@ const localesForSwitcher = i18nConfig.locales.map(l => ({
|
|
|
40
41
|
code: l.code,
|
|
41
42
|
name: l.name,
|
|
42
43
|
}));
|
|
44
|
+
|
|
45
|
+
// Get base URL for prefixing links
|
|
46
|
+
const base = import.meta.env.BASE_URL;
|
|
43
47
|
---
|
|
44
48
|
|
|
45
49
|
<header class="sticky top-0 z-50 bg-white/80 dark:bg-slate-900/80 backdrop-blur-sm border-b border-slate-200 dark:border-slate-700">
|
|
46
50
|
<div class="container mx-auto px-4">
|
|
47
51
|
<nav class="flex items-center justify-between h-16">
|
|
48
52
|
<div class="flex items-center space-x-4">
|
|
49
|
-
<a href=
|
|
53
|
+
<a href={withBase('/', base)} class="flex items-center space-x-3 hover:opacity-80 transition-opacity">
|
|
50
54
|
{(localeSiteConfig.avatar || siteConfig.avatar) && (
|
|
51
55
|
<img
|
|
52
|
-
src={localeSiteConfig.avatar || siteConfig.avatar}
|
|
56
|
+
src={withBase(localeSiteConfig.avatar || siteConfig.avatar || '', base)}
|
|
53
57
|
alt={localeSiteConfig.title || siteConfig.title}
|
|
54
58
|
class="w-8 h-8 rounded-full"
|
|
55
59
|
/>
|
|
@@ -70,9 +74,9 @@ const localesForSwitcher = i18nConfig.locales.map(l => ({
|
|
|
70
74
|
<div class="hidden md:flex items-center space-x-8">
|
|
71
75
|
{menu.map((item) => (
|
|
72
76
|
<a
|
|
73
|
-
href={item.href}
|
|
77
|
+
href={withBase(item.href, base)}
|
|
74
78
|
class={`text-sm font-medium transition-colors hover:text-primary-500 ${
|
|
75
|
-
currentPath === item.href || (item.href !== '/' && currentPath.startsWith(item.href))
|
|
79
|
+
currentPath === withBase(item.href, base) || (item.href !== '/' && currentPath.startsWith(withBase(item.href, base)))
|
|
76
80
|
? 'text-primary-500'
|
|
77
81
|
: 'text-slate-700 dark:text-slate-300'
|
|
78
82
|
}`}
|
|
@@ -23,7 +23,8 @@ const { currentPath = Astro.url.pathname, i18nConfig = defaultI18nConfig } = Ast
|
|
|
23
23
|
const currentLocale = getLocaleFromPath(currentPath, i18nConfig);
|
|
24
24
|
const localeConfig = getLocaleConfig(currentLocale, i18nConfig);
|
|
25
25
|
const ui = localeConfig.ui;
|
|
26
|
-
const
|
|
26
|
+
const base = import.meta.env.BASE_URL;
|
|
27
|
+
const localePrefix = getLocalePrefix(currentLocale, i18nConfig, base);
|
|
27
28
|
|
|
28
29
|
// Get locale-specific sidebar config (already merged with defaults in getLocaleConfig)
|
|
29
30
|
const sidebarConfig = localeConfig.sidebar;
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
getAlternateLinks,
|
|
11
11
|
getTextDirection,
|
|
12
12
|
isMultiLanguageEnabled,
|
|
13
|
+
withBase,
|
|
13
14
|
t,
|
|
14
15
|
type I18nConfig,
|
|
15
16
|
} from '../utils/i18n';
|
|
@@ -69,6 +70,9 @@ const faviconSvgExists = fs.existsSync(path.join(publicDir, 'favicon.svg'));
|
|
|
69
70
|
const faviconIcoExists = fs.existsSync(path.join(publicDir, 'favicon.ico'));
|
|
70
71
|
const faviconHref = faviconSvgExists ? '/favicon.svg' : faviconIcoExists ? '/favicon.ico' : siteConfig.avatar;
|
|
71
72
|
const faviconType = faviconSvgExists ? 'image/svg+xml' : faviconIcoExists ? 'image/x-icon' : 'image/jpeg';
|
|
73
|
+
|
|
74
|
+
// Get base URL for prefixing links
|
|
75
|
+
const base = import.meta.env.BASE_URL;
|
|
72
76
|
---
|
|
73
77
|
|
|
74
78
|
<!DOCTYPE html>
|
|
@@ -77,7 +81,7 @@ const faviconType = faviconSvgExists ? 'image/svg+xml' : faviconIcoExists ? 'ima
|
|
|
77
81
|
<meta charset="UTF-8" />
|
|
78
82
|
<meta name="description" content={description} />
|
|
79
83
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
80
|
-
<link rel="icon" type={faviconType} href={faviconHref} />
|
|
84
|
+
<link rel="icon" type={faviconType} href={withBase(faviconHref || '', base)} />
|
|
81
85
|
<meta name="generator" content={Astro.generator} />
|
|
82
86
|
|
|
83
87
|
<!-- SEO -->
|
|
@@ -115,7 +119,7 @@ const faviconType = faviconSvgExists ? 'image/svg+xml' : faviconIcoExists ? 'ima
|
|
|
115
119
|
<meta name="twitter:image" content={fullImage} />
|
|
116
120
|
|
|
117
121
|
<!-- RSS -->
|
|
118
|
-
<link rel="alternate" type="application/rss+xml" title={siteTitle} href={rssPath} />
|
|
122
|
+
<link rel="alternate" type="application/rss+xml" title={siteTitle} href={withBase(rssPath, base)} />
|
|
119
123
|
|
|
120
124
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
121
125
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
@@ -158,10 +162,10 @@ const faviconType = faviconSvgExists ? 'image/svg+xml' : faviconIcoExists ? 'ima
|
|
|
158
162
|
</div>
|
|
159
163
|
|
|
160
164
|
<!-- Mermaid -->
|
|
161
|
-
<script src=
|
|
165
|
+
<script src={withBase('/js/mermaid-container.js', base)} is:inline></script>
|
|
162
166
|
|
|
163
167
|
<!-- Tabs -->
|
|
164
|
-
<script src=
|
|
168
|
+
<script src={withBase('/js/tabs-init.js', base)} is:inline></script>
|
|
165
169
|
|
|
166
170
|
<!-- Store i18n data for client-side scripts -->
|
|
167
171
|
<script is:inline define:vars={{ locale: currentLocale, uiTranslations: ui }}>
|
|
@@ -43,7 +43,8 @@ const i18nConfig = virtualI18nConfig || defaultI18nConfig;
|
|
|
43
43
|
const currentLocale = getLocaleFromPath(Astro.url.pathname, i18nConfig);
|
|
44
44
|
const localeConfig = getLocaleConfig(currentLocale, i18nConfig);
|
|
45
45
|
const ui = localeConfig.ui;
|
|
46
|
-
const
|
|
46
|
+
const base = import.meta.env.BASE_URL;
|
|
47
|
+
const localePrefix = getLocalePrefix(currentLocale, i18nConfig, base);
|
|
47
48
|
|
|
48
49
|
// 获取该月的所有文章
|
|
49
50
|
const allPostsCollection = await getCollection('posts', ({ data }) => !data.draft);
|
|
@@ -10,7 +10,8 @@ const i18nConfig = virtualI18nConfig || defaultI18nConfig;
|
|
|
10
10
|
const currentLocale = getLocaleFromPath(Astro.url.pathname, i18nConfig);
|
|
11
11
|
const localeConfig = getLocaleConfig(currentLocale, i18nConfig);
|
|
12
12
|
const ui = localeConfig.ui;
|
|
13
|
-
const
|
|
13
|
+
const base = import.meta.env.BASE_URL;
|
|
14
|
+
const localePrefix = getLocalePrefix(currentLocale, i18nConfig, base);
|
|
14
15
|
|
|
15
16
|
// 获取所有非草稿文章
|
|
16
17
|
const allPostsCollection = await getCollection('posts', ({ data }) => !data.draft);
|
|
@@ -38,7 +38,8 @@ const i18nConfig = virtualI18nConfig || defaultI18nConfig;
|
|
|
38
38
|
const currentLocale = getLocaleFromPath(Astro.url.pathname, i18nConfig);
|
|
39
39
|
const localeConfig = getLocaleConfig(currentLocale, i18nConfig);
|
|
40
40
|
const ui = localeConfig.ui;
|
|
41
|
-
const
|
|
41
|
+
const base = import.meta.env.BASE_URL;
|
|
42
|
+
const localePrefix = getLocalePrefix(currentLocale, i18nConfig, base);
|
|
42
43
|
|
|
43
44
|
// 获取所有文章并筛选包含该分类的文章
|
|
44
45
|
const allPostsCollection = await getCollection('posts', ({ data }) => !data.draft);
|
|
@@ -10,7 +10,8 @@ const i18nConfig = virtualI18nConfig || defaultI18nConfig;
|
|
|
10
10
|
const currentLocale = getLocaleFromPath(Astro.url.pathname, i18nConfig);
|
|
11
11
|
const localeConfig = getLocaleConfig(currentLocale, i18nConfig);
|
|
12
12
|
const ui = localeConfig.ui;
|
|
13
|
-
const
|
|
13
|
+
const base = import.meta.env.BASE_URL;
|
|
14
|
+
const localePrefix = getLocalePrefix(currentLocale, i18nConfig, base);
|
|
14
15
|
|
|
15
16
|
// 从文章集合动态获取所有分类
|
|
16
17
|
const allPostsCollection = await getCollection('posts', ({ data }) => !data.draft);
|
|
@@ -156,7 +156,8 @@ const i18nConfig = virtualI18nConfig || defaultI18nConfig;
|
|
|
156
156
|
const currentLocale = getLocaleFromPath(Astro.url.pathname, i18nConfig);
|
|
157
157
|
const localeConfig = getLocaleConfig(currentLocale, i18nConfig);
|
|
158
158
|
const ui = localeConfig.ui;
|
|
159
|
-
const
|
|
159
|
+
const base = import.meta.env.BASE_URL;
|
|
160
|
+
const localePrefix = getLocalePrefix(currentLocale, i18nConfig, base);
|
|
160
161
|
|
|
161
162
|
// Get the current slug from URL
|
|
162
163
|
const urlPath = Astro.url.pathname;
|
|
@@ -13,7 +13,8 @@ const i18nConfig = virtualI18nConfig || defaultI18nConfig;
|
|
|
13
13
|
const currentLocale = getLocaleFromPath(Astro.url.pathname, i18nConfig);
|
|
14
14
|
const localeConfig = getLocaleConfig(currentLocale, i18nConfig);
|
|
15
15
|
const ui = localeConfig.ui;
|
|
16
|
-
const
|
|
16
|
+
const base = import.meta.env.BASE_URL;
|
|
17
|
+
const localePrefix = getLocalePrefix(currentLocale, i18nConfig, base);
|
|
17
18
|
|
|
18
19
|
// 从新的内容目录获取文章数据
|
|
19
20
|
const allPostsCollection = await getCollection('posts');
|
|
@@ -28,7 +28,8 @@ const i18nConfig = virtualI18nConfig || defaultI18nConfig;
|
|
|
28
28
|
const currentLocale = getLocaleFromPath(Astro.url.pathname, i18nConfig);
|
|
29
29
|
const localeConfig = getLocaleConfig(currentLocale, i18nConfig);
|
|
30
30
|
const ui = localeConfig.ui;
|
|
31
|
-
const
|
|
31
|
+
const base = import.meta.env.BASE_URL;
|
|
32
|
+
const localePrefix = getLocalePrefix(currentLocale, i18nConfig, base);
|
|
32
33
|
|
|
33
34
|
// 从新的内容目录获取文章数据
|
|
34
35
|
const allPostsCollection = await getCollection('posts');
|
|
@@ -10,7 +10,8 @@ const i18nConfig = virtualI18nConfig || defaultI18nConfig;
|
|
|
10
10
|
const currentLocale = getLocaleFromPath(Astro.url.pathname, i18nConfig);
|
|
11
11
|
const localeConfig = getLocaleConfig(currentLocale, i18nConfig);
|
|
12
12
|
const ui = localeConfig.ui;
|
|
13
|
-
const
|
|
13
|
+
const base = import.meta.env.BASE_URL;
|
|
14
|
+
const localePrefix = getLocalePrefix(currentLocale, i18nConfig, base);
|
|
14
15
|
|
|
15
16
|
// 获取所有非草稿的 slides
|
|
16
17
|
const slides = (await getCollection('slides', ({ data }) => !data.draft))
|
|
@@ -38,7 +38,8 @@ const i18nConfig = virtualI18nConfig || defaultI18nConfig;
|
|
|
38
38
|
const currentLocale = getLocaleFromPath(Astro.url.pathname, i18nConfig);
|
|
39
39
|
const localeConfig = getLocaleConfig(currentLocale, i18nConfig);
|
|
40
40
|
const ui = localeConfig.ui;
|
|
41
|
-
const
|
|
41
|
+
const base = import.meta.env.BASE_URL;
|
|
42
|
+
const localePrefix = getLocalePrefix(currentLocale, i18nConfig, base);
|
|
42
43
|
|
|
43
44
|
// 获取所有文章并筛选包含该标签的文章
|
|
44
45
|
const allPostsCollection = await getCollection('posts', ({ data }) => !data.draft);
|
|
@@ -11,7 +11,8 @@ const i18nConfig = virtualI18nConfig || defaultI18nConfig;
|
|
|
11
11
|
const currentLocale = getLocaleFromPath(Astro.url.pathname, i18nConfig);
|
|
12
12
|
const localeConfig = getLocaleConfig(currentLocale, i18nConfig);
|
|
13
13
|
const ui = localeConfig.ui;
|
|
14
|
-
const
|
|
14
|
+
const base = import.meta.env.BASE_URL;
|
|
15
|
+
const localePrefix = getLocalePrefix(currentLocale, i18nConfig, base);
|
|
15
16
|
|
|
16
17
|
// 从文章集合动态获取所有标签
|
|
17
18
|
const allPostsCollection = await getCollection('posts', ({ data }) => !data.draft);
|
package/src/utils/i18n.ts
CHANGED
|
@@ -353,15 +353,38 @@ export function isMultiLanguageEnabled(
|
|
|
353
353
|
/**
|
|
354
354
|
* Get prefix for a locale in routes
|
|
355
355
|
* Returns empty string for default locale if prefixDefaultLocale is false
|
|
356
|
+
* If base is provided, it will be prepended to the locale prefix
|
|
357
|
+
*
|
|
358
|
+
* @example
|
|
359
|
+
* // Without base
|
|
360
|
+
* getLocalePrefix('en', config) // '' (for default locale)
|
|
361
|
+
* getLocalePrefix('zh-CN', config) // '/zh-CN'
|
|
362
|
+
*
|
|
363
|
+
* // With base '/my-blog'
|
|
364
|
+
* getLocalePrefix('en', config, '/my-blog') // '/my-blog'
|
|
365
|
+
* getLocalePrefix('zh-CN', config, '/my-blog') // '/my-blog/zh-CN'
|
|
356
366
|
*/
|
|
357
367
|
export function getLocalePrefix(
|
|
358
368
|
locale: string,
|
|
359
|
-
config: I18nConfig = defaultI18nConfig
|
|
369
|
+
config: I18nConfig = defaultI18nConfig,
|
|
370
|
+
base?: string
|
|
360
371
|
): string {
|
|
361
|
-
|
|
362
|
-
|
|
372
|
+
// Normalize base: remove trailing slash
|
|
373
|
+
const normalizedBase = base ? base.replace(/\/$/, '') : '';
|
|
374
|
+
|
|
375
|
+
// Get locale prefix
|
|
376
|
+
let localePrefix = '';
|
|
377
|
+
if (locale !== config.defaultLocale || config.routing.prefixDefaultLocale) {
|
|
378
|
+
localePrefix = `/${locale}`;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// If base is just '/' or empty, return locale prefix as before
|
|
382
|
+
if (!normalizedBase || normalizedBase === '') {
|
|
383
|
+
return localePrefix;
|
|
363
384
|
}
|
|
364
|
-
|
|
385
|
+
|
|
386
|
+
// Combine base and locale prefix
|
|
387
|
+
return `${normalizedBase}${localePrefix}`;
|
|
365
388
|
}
|
|
366
389
|
|
|
367
390
|
/**
|
|
@@ -406,6 +429,62 @@ export function filterPostsByLocale<T extends { id: string }>(
|
|
|
406
429
|
});
|
|
407
430
|
}
|
|
408
431
|
|
|
432
|
+
/**
|
|
433
|
+
* Add base URL prefix to a path
|
|
434
|
+
* This is used when the site is deployed to a subdirectory (e.g., /jet-w.astro-blog/)
|
|
435
|
+
*
|
|
436
|
+
* @example
|
|
437
|
+
* // If BASE_URL is '/jet-w.astro-blog'
|
|
438
|
+
* withBase('/posts') // '/jet-w.astro-blog/posts'
|
|
439
|
+
* withBase('/') // '/jet-w.astro-blog/'
|
|
440
|
+
*
|
|
441
|
+
* // If BASE_URL is '/'
|
|
442
|
+
* withBase('/posts') // '/posts'
|
|
443
|
+
*/
|
|
444
|
+
export function withBase(path: string, base?: string): string {
|
|
445
|
+
// Get base URL - in Astro components, pass import.meta.env.BASE_URL
|
|
446
|
+
// Remove trailing slash from base
|
|
447
|
+
const baseUrl = (base || '/').replace(/\/$/, '');
|
|
448
|
+
|
|
449
|
+
// If base is empty or just '/', return path as-is
|
|
450
|
+
if (!baseUrl || baseUrl === '') {
|
|
451
|
+
return path;
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// Ensure path starts with /
|
|
455
|
+
const normalizedPath = path.startsWith('/') ? path : `/${path}`;
|
|
456
|
+
|
|
457
|
+
// If path is just '/', return base with trailing slash
|
|
458
|
+
if (normalizedPath === '/') {
|
|
459
|
+
return `${baseUrl}/`;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
return `${baseUrl}${normalizedPath}`;
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
/**
|
|
466
|
+
* Remove base URL prefix from a path
|
|
467
|
+
* Useful for getting the actual path without base prefix
|
|
468
|
+
*
|
|
469
|
+
* @example
|
|
470
|
+
* // If BASE_URL is '/jet-w.astro-blog'
|
|
471
|
+
* removeBase('/jet-w.astro-blog/posts', '/jet-w.astro-blog') // '/posts'
|
|
472
|
+
*/
|
|
473
|
+
export function removeBase(path: string, base?: string): string {
|
|
474
|
+
const baseUrl = (base || '/').replace(/\/$/, '');
|
|
475
|
+
|
|
476
|
+
if (!baseUrl || baseUrl === '') {
|
|
477
|
+
return path;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
if (path.startsWith(baseUrl)) {
|
|
481
|
+
const rest = path.slice(baseUrl.length);
|
|
482
|
+
return rest || '/';
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
return path;
|
|
486
|
+
}
|
|
487
|
+
|
|
409
488
|
// Re-export types and config functions
|
|
410
489
|
export type { I18nConfig, Locale, LocaleConfig, UITranslations } from '../config/i18n';
|
|
411
490
|
export {
|