@jant/core 0.1.2 → 0.2.0
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/app.d.ts +34 -0
- package/dist/app.d.ts.map +1 -0
- package/dist/app.js +474 -0
- package/dist/assets/datastar.min.js +1775 -0
- package/dist/auth.d.ts +23 -0
- package/dist/auth.d.ts.map +1 -0
- package/dist/auth.js +34 -0
- package/{src/client.ts → dist/client.d.ts} +1 -1
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +4 -0
- package/dist/db/index.d.ts +10 -0
- package/dist/db/index.d.ts.map +1 -0
- package/dist/db/index.js +10 -0
- package/dist/db/schema.d.ts +1507 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/schema.js +183 -0
- package/{src/i18n/Trans.tsx → dist/i18n/Trans.d.ts} +4 -10
- package/dist/i18n/Trans.d.ts.map +1 -0
- package/dist/i18n/Trans.js +24 -0
- package/dist/i18n/context.d.ts +69 -0
- package/dist/i18n/context.d.ts.map +1 -0
- package/dist/i18n/context.js +61 -0
- package/dist/i18n/detect.d.ts +31 -0
- package/dist/i18n/detect.d.ts.map +1 -0
- package/dist/i18n/detect.js +77 -0
- package/{src/i18n/i18n.ts → dist/i18n/i18n.d.ts} +5 -25
- package/dist/i18n/i18n.d.ts.map +1 -0
- package/dist/i18n/i18n.js +55 -0
- package/dist/i18n/index.d.ts +41 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/{src/i18n/index.ts → dist/i18n/index.js} +3 -24
- package/dist/i18n/locales/en.d.ts +3 -0
- package/dist/i18n/locales/en.d.ts.map +1 -0
- package/dist/i18n/locales/en.js +1 -0
- package/dist/i18n/locales/zh-Hans.d.ts +3 -0
- package/dist/i18n/locales/zh-Hans.d.ts.map +1 -0
- package/dist/i18n/locales/zh-Hans.js +1 -0
- package/dist/i18n/locales/zh-Hant.d.ts +3 -0
- package/dist/i18n/locales/zh-Hant.d.ts.map +1 -0
- package/dist/i18n/locales/zh-Hant.js +1 -0
- package/dist/i18n/locales.d.ts +11 -0
- package/dist/i18n/locales.d.ts.map +1 -0
- package/dist/i18n/locales.js +13 -0
- package/dist/i18n/middleware.d.ts +24 -0
- package/dist/i18n/middleware.d.ts.map +1 -0
- package/dist/i18n/middleware.js +41 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/{src/index.ts → dist/index.js} +1 -28
- package/dist/lib/assets.d.ts +19 -0
- package/dist/lib/assets.d.ts.map +1 -0
- package/dist/lib/assets.js +33 -0
- package/dist/lib/constants.d.ts +36 -0
- package/dist/lib/constants.d.ts.map +1 -0
- package/dist/lib/constants.js +50 -0
- package/{src/lib/image.ts → dist/lib/image.d.ts} +13 -47
- package/dist/lib/image.d.ts.map +1 -0
- package/dist/lib/image.js +77 -0
- package/{src/lib/index.ts → dist/lib/index.d.ts} +1 -1
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/index.js +7 -0
- package/dist/lib/markdown.d.ts +60 -0
- package/dist/lib/markdown.d.ts.map +1 -0
- package/{src/lib/markdown.ts → dist/lib/markdown.js} +16 -26
- package/dist/lib/schemas.d.ts +113 -0
- package/dist/lib/schemas.d.ts.map +1 -0
- package/dist/lib/schemas.js +71 -0
- package/dist/lib/sqid.d.ts +60 -0
- package/dist/lib/sqid.d.ts.map +1 -0
- package/{src/lib/sqid.ts → dist/lib/sqid.js} +15 -22
- package/dist/lib/sse.d.ts +95 -0
- package/dist/lib/sse.d.ts.map +1 -0
- package/dist/lib/sse.js +81 -0
- package/dist/lib/time.d.ts +90 -0
- package/dist/lib/time.d.ts.map +1 -0
- package/{src/lib/time.ts → dist/lib/time.js} +20 -33
- package/{src/lib/url.ts → dist/lib/url.d.ts} +5 -30
- package/dist/lib/url.d.ts.map +1 -0
- package/dist/lib/url.js +89 -0
- package/dist/middleware/auth.d.ts +24 -0
- package/dist/middleware/auth.d.ts.map +1 -0
- package/dist/middleware/auth.js +52 -0
- package/dist/routes/api/posts.d.ts +13 -0
- package/dist/routes/api/posts.d.ts.map +1 -0
- package/dist/routes/api/posts.js +124 -0
- package/dist/routes/api/search.d.ts +13 -0
- package/dist/routes/api/search.d.ts.map +1 -0
- package/dist/routes/api/search.js +49 -0
- package/dist/routes/api/upload.d.ts +16 -0
- package/dist/routes/api/upload.d.ts.map +1 -0
- package/dist/routes/api/upload.js +227 -0
- package/dist/routes/dash/collections.d.ts +13 -0
- package/dist/routes/dash/collections.d.ts.map +1 -0
- package/dist/routes/dash/collections.js +512 -0
- package/dist/routes/dash/index.d.ts +15 -0
- package/dist/routes/dash/index.d.ts.map +1 -0
- package/dist/routes/dash/index.js +117 -0
- package/dist/routes/dash/media.d.ts +16 -0
- package/dist/routes/dash/media.d.ts.map +1 -0
- package/dist/routes/dash/media.js +589 -0
- package/dist/routes/dash/pages.d.ts +15 -0
- package/dist/routes/dash/pages.d.ts.map +1 -0
- package/dist/routes/dash/pages.js +290 -0
- package/dist/routes/dash/posts.d.ts +13 -0
- package/dist/routes/dash/posts.d.ts.map +1 -0
- package/dist/routes/dash/posts.js +226 -0
- package/dist/routes/dash/redirects.d.ts +13 -0
- package/dist/routes/dash/redirects.d.ts.map +1 -0
- package/dist/routes/dash/redirects.js +237 -0
- package/dist/routes/dash/settings.d.ts +13 -0
- package/dist/routes/dash/settings.d.ts.map +1 -0
- package/dist/routes/dash/settings.js +154 -0
- package/dist/routes/feed/rss.d.ts +13 -0
- package/dist/routes/feed/rss.d.ts.map +1 -0
- package/dist/routes/feed/rss.js +95 -0
- package/dist/routes/feed/sitemap.d.ts +13 -0
- package/dist/routes/feed/sitemap.d.ts.map +1 -0
- package/dist/routes/feed/sitemap.js +59 -0
- package/dist/routes/pages/archive.d.ts +15 -0
- package/dist/routes/pages/archive.d.ts.map +1 -0
- package/dist/routes/pages/archive.js +255 -0
- package/dist/routes/pages/collection.d.ts +13 -0
- package/dist/routes/pages/collection.d.ts.map +1 -0
- package/dist/routes/pages/collection.js +93 -0
- package/dist/routes/pages/home.d.ts +13 -0
- package/dist/routes/pages/home.d.ts.map +1 -0
- package/dist/routes/pages/home.js +122 -0
- package/dist/routes/pages/page.d.ts +15 -0
- package/dist/routes/pages/page.d.ts.map +1 -0
- package/dist/routes/pages/page.js +69 -0
- package/dist/routes/pages/post.d.ts +13 -0
- package/dist/routes/pages/post.d.ts.map +1 -0
- package/dist/routes/pages/post.js +90 -0
- package/dist/routes/pages/search.d.ts +13 -0
- package/dist/routes/pages/search.d.ts.map +1 -0
- package/dist/routes/pages/search.js +180 -0
- package/dist/services/collection.d.ts +31 -0
- package/dist/services/collection.d.ts.map +1 -0
- package/dist/services/collection.js +108 -0
- package/dist/services/index.d.ts +28 -0
- package/dist/services/index.d.ts.map +1 -0
- package/dist/services/index.js +20 -0
- package/dist/services/media.d.ts +27 -0
- package/dist/services/media.d.ts.map +1 -0
- package/dist/services/media.js +62 -0
- package/dist/services/post.d.ts +31 -0
- package/dist/services/post.d.ts.map +1 -0
- package/dist/services/post.js +191 -0
- package/dist/services/redirect.d.ts +15 -0
- package/dist/services/redirect.d.ts.map +1 -0
- package/dist/services/redirect.js +48 -0
- package/dist/services/search.d.ts +26 -0
- package/dist/services/search.d.ts.map +1 -0
- package/dist/services/search.js +61 -0
- package/dist/services/settings.d.ts +17 -0
- package/dist/services/settings.d.ts.map +1 -0
- package/dist/services/settings.js +65 -0
- package/dist/theme/components/ActionButtons.d.ts +43 -0
- package/dist/theme/components/ActionButtons.d.ts.map +1 -0
- package/dist/theme/components/ActionButtons.js +50 -0
- package/dist/theme/components/CrudPageHeader.d.ts +23 -0
- package/dist/theme/components/CrudPageHeader.d.ts.map +1 -0
- package/dist/theme/components/CrudPageHeader.js +22 -0
- package/dist/theme/components/DangerZone.d.ts +36 -0
- package/dist/theme/components/DangerZone.d.ts.map +1 -0
- package/dist/theme/components/DangerZone.js +39 -0
- package/dist/theme/components/EmptyState.d.ts +27 -0
- package/dist/theme/components/EmptyState.d.ts.map +1 -0
- package/dist/theme/components/EmptyState.js +27 -0
- package/dist/theme/components/ListItemRow.d.ts +15 -0
- package/dist/theme/components/ListItemRow.d.ts.map +1 -0
- package/dist/theme/components/ListItemRow.js +21 -0
- package/dist/theme/components/PageForm.d.ts +14 -0
- package/dist/theme/components/PageForm.d.ts.map +1 -0
- package/dist/theme/components/PageForm.js +173 -0
- package/dist/theme/components/Pagination.d.ts +46 -0
- package/dist/theme/components/Pagination.d.ts.map +1 -0
- package/dist/theme/components/Pagination.js +159 -0
- package/dist/theme/components/PostForm.d.ts +12 -0
- package/dist/theme/components/PostForm.d.ts.map +1 -0
- package/dist/theme/components/PostForm.js +230 -0
- package/dist/theme/components/PostList.d.ts +10 -0
- package/dist/theme/components/PostList.d.ts.map +1 -0
- package/dist/theme/components/PostList.js +73 -0
- package/dist/theme/components/ThreadView.d.ts +15 -0
- package/dist/theme/components/ThreadView.d.ts.map +1 -0
- package/dist/theme/components/ThreadView.js +111 -0
- package/dist/theme/components/TypeBadge.d.ts +12 -0
- package/dist/theme/components/TypeBadge.d.ts.map +1 -0
- package/dist/theme/components/TypeBadge.js +39 -0
- package/dist/theme/components/VisibilityBadge.d.ts +12 -0
- package/dist/theme/components/VisibilityBadge.d.ts.map +1 -0
- package/dist/theme/components/VisibilityBadge.js +37 -0
- package/{src/theme/components/index.ts → dist/theme/components/index.d.ts} +1 -0
- package/dist/theme/components/index.d.ts.map +1 -0
- package/dist/theme/components/index.js +12 -0
- package/dist/theme/index.d.ts +21 -0
- package/dist/theme/index.d.ts.map +1 -0
- package/{src/theme/index.ts → dist/theme/index.js} +1 -4
- package/dist/theme/layouts/BaseLayout.d.ts +16 -0
- package/dist/theme/layouts/BaseLayout.d.ts.map +1 -0
- package/dist/theme/layouts/BaseLayout.js +58 -0
- package/dist/theme/layouts/DashLayout.d.ts +15 -0
- package/dist/theme/layouts/DashLayout.d.ts.map +1 -0
- package/dist/theme/layouts/DashLayout.js +139 -0
- package/{src/theme/layouts/index.ts → dist/theme/layouts/index.d.ts} +1 -0
- package/dist/theme/layouts/index.d.ts.map +1 -0
- package/dist/theme/layouts/index.js +2 -0
- package/dist/theme/styles/main.css +2 -0
- package/dist/types.d.ts +179 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +19 -0
- package/package.json +26 -26
- package/drizzle.config.ts +0 -10
- package/lingui.config.ts +0 -16
- package/src/app.tsx +0 -377
- package/src/assets/datastar.min.js +0 -8
- package/src/auth.ts +0 -38
- package/src/db/index.ts +0 -14
- package/src/db/migrations/0000_solid_moon_knight.sql +0 -118
- package/src/db/migrations/0001_add_search_fts.sql +0 -40
- package/src/db/migrations/0002_collection_path.sql +0 -2
- package/src/db/migrations/0003_collection_path_nullable.sql +0 -21
- package/src/db/migrations/0004_media_uuid.sql +0 -35
- package/src/db/migrations/meta/0000_snapshot.json +0 -784
- package/src/db/migrations/meta/_journal.json +0 -41
- package/src/db/schema.ts +0 -159
- package/src/i18n/EXAMPLES.md +0 -235
- package/src/i18n/README.md +0 -296
- package/src/i18n/context.tsx +0 -101
- package/src/i18n/detect.ts +0 -100
- package/src/i18n/locales/en.po +0 -875
- package/src/i18n/locales/en.ts +0 -1
- package/src/i18n/locales/zh-Hans.po +0 -875
- package/src/i18n/locales/zh-Hans.ts +0 -1
- package/src/i18n/locales/zh-Hant.po +0 -875
- package/src/i18n/locales/zh-Hant.ts +0 -1
- package/src/i18n/locales.ts +0 -14
- package/src/i18n/middleware.ts +0 -59
- package/src/lib/assets.ts +0 -47
- package/src/lib/constants.ts +0 -67
- package/src/lib/schemas.ts +0 -92
- package/src/lib/sse.ts +0 -152
- package/src/middleware/auth.ts +0 -59
- package/src/routes/api/posts.ts +0 -127
- package/src/routes/api/search.ts +0 -53
- package/src/routes/api/upload.ts +0 -240
- package/src/routes/dash/collections.tsx +0 -341
- package/src/routes/dash/index.tsx +0 -89
- package/src/routes/dash/media.tsx +0 -551
- package/src/routes/dash/pages.tsx +0 -245
- package/src/routes/dash/posts.tsx +0 -202
- package/src/routes/dash/redirects.tsx +0 -155
- package/src/routes/dash/settings.tsx +0 -93
- package/src/routes/feed/rss.ts +0 -119
- package/src/routes/feed/sitemap.ts +0 -75
- package/src/routes/pages/archive.tsx +0 -223
- package/src/routes/pages/collection.tsx +0 -79
- package/src/routes/pages/home.tsx +0 -93
- package/src/routes/pages/page.tsx +0 -64
- package/src/routes/pages/post.tsx +0 -81
- package/src/routes/pages/search.tsx +0 -162
- package/src/services/collection.ts +0 -180
- package/src/services/index.ts +0 -40
- package/src/services/media.ts +0 -97
- package/src/services/post.ts +0 -279
- package/src/services/redirect.ts +0 -74
- package/src/services/search.ts +0 -117
- package/src/services/settings.ts +0 -76
- package/src/theme/components/ActionButtons.tsx +0 -98
- package/src/theme/components/CrudPageHeader.tsx +0 -48
- package/src/theme/components/DangerZone.tsx +0 -77
- package/src/theme/components/EmptyState.tsx +0 -56
- package/src/theme/components/ListItemRow.tsx +0 -24
- package/src/theme/components/PageForm.tsx +0 -114
- package/src/theme/components/Pagination.tsx +0 -196
- package/src/theme/components/PostForm.tsx +0 -122
- package/src/theme/components/PostList.tsx +0 -68
- package/src/theme/components/ThreadView.tsx +0 -118
- package/src/theme/components/TypeBadge.tsx +0 -28
- package/src/theme/components/VisibilityBadge.tsx +0 -33
- package/src/theme/layouts/BaseLayout.tsx +0 -49
- package/src/theme/layouts/DashLayout.tsx +0 -108
- package/src/theme/styles/main.css +0 -52
- package/src/types.ts +0 -222
- package/tsconfig.json +0 -16
- package/vite.config.ts +0 -82
- package/wrangler.toml +0 -21
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/db/schema.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAQH,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAmBhB,CAAC;AAMH,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAYhB,CAAC;AAMH,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAOtB,CAAC;AAMH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAY3B,CAAC;AAMF,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAMpB,CAAC;AAMH,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAInB,CAAC;AAOH,eAAO,MAAM,IAAI;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EASf,CAAC;AAEH,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAWlB,CAAC;AAEH,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAgBlB,CAAC;AAEH,eAAO,MAAM,YAAY;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAOvB,CAAC"}
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Drizzle Schema
|
|
3
|
+
*
|
|
4
|
+
* Database schema for Jant
|
|
5
|
+
*/ import { sqliteTable, text, integer, primaryKey } from "drizzle-orm/sqlite-core";
|
|
6
|
+
// =============================================================================
|
|
7
|
+
// Posts
|
|
8
|
+
// =============================================================================
|
|
9
|
+
export const posts = sqliteTable("posts", {
|
|
10
|
+
id: integer("id").primaryKey({
|
|
11
|
+
autoIncrement: true
|
|
12
|
+
}),
|
|
13
|
+
type: text("type", {
|
|
14
|
+
enum: [
|
|
15
|
+
"note",
|
|
16
|
+
"article",
|
|
17
|
+
"link",
|
|
18
|
+
"quote",
|
|
19
|
+
"image",
|
|
20
|
+
"page"
|
|
21
|
+
]
|
|
22
|
+
}).notNull(),
|
|
23
|
+
visibility: text("visibility", {
|
|
24
|
+
enum: [
|
|
25
|
+
"featured",
|
|
26
|
+
"quiet",
|
|
27
|
+
"unlisted",
|
|
28
|
+
"draft"
|
|
29
|
+
]
|
|
30
|
+
}).notNull().default("quiet"),
|
|
31
|
+
title: text("title"),
|
|
32
|
+
path: text("path"),
|
|
33
|
+
content: text("content"),
|
|
34
|
+
contentHtml: text("content_html"),
|
|
35
|
+
sourceUrl: text("source_url"),
|
|
36
|
+
sourceName: text("source_name"),
|
|
37
|
+
sourceDomain: text("source_domain"),
|
|
38
|
+
replyToId: integer("reply_to_id"),
|
|
39
|
+
threadId: integer("thread_id"),
|
|
40
|
+
deletedAt: integer("deleted_at"),
|
|
41
|
+
publishedAt: integer("published_at").notNull(),
|
|
42
|
+
createdAt: integer("created_at").notNull(),
|
|
43
|
+
updatedAt: integer("updated_at").notNull()
|
|
44
|
+
});
|
|
45
|
+
// =============================================================================
|
|
46
|
+
// Media
|
|
47
|
+
// =============================================================================
|
|
48
|
+
export const media = sqliteTable("media", {
|
|
49
|
+
id: text("id").primaryKey(),
|
|
50
|
+
postId: integer("post_id").references(()=>posts.id),
|
|
51
|
+
filename: text("filename").notNull(),
|
|
52
|
+
originalName: text("original_name").notNull(),
|
|
53
|
+
mimeType: text("mime_type").notNull(),
|
|
54
|
+
size: integer("size").notNull(),
|
|
55
|
+
r2Key: text("r2_key").notNull(),
|
|
56
|
+
width: integer("width"),
|
|
57
|
+
height: integer("height"),
|
|
58
|
+
alt: text("alt"),
|
|
59
|
+
createdAt: integer("created_at").notNull()
|
|
60
|
+
});
|
|
61
|
+
// =============================================================================
|
|
62
|
+
// Collections
|
|
63
|
+
// =============================================================================
|
|
64
|
+
export const collections = sqliteTable("collections", {
|
|
65
|
+
id: integer("id").primaryKey({
|
|
66
|
+
autoIncrement: true
|
|
67
|
+
}),
|
|
68
|
+
path: text("path").unique(),
|
|
69
|
+
title: text("title").notNull(),
|
|
70
|
+
description: text("description"),
|
|
71
|
+
createdAt: integer("created_at").notNull(),
|
|
72
|
+
updatedAt: integer("updated_at").notNull()
|
|
73
|
+
});
|
|
74
|
+
// =============================================================================
|
|
75
|
+
// Post-Collections (Many-to-Many)
|
|
76
|
+
// =============================================================================
|
|
77
|
+
export const postCollections = sqliteTable("post_collections", {
|
|
78
|
+
postId: integer("post_id").notNull().references(()=>posts.id),
|
|
79
|
+
collectionId: integer("collection_id").notNull().references(()=>collections.id),
|
|
80
|
+
addedAt: integer("added_at").notNull()
|
|
81
|
+
}, (table)=>[
|
|
82
|
+
primaryKey({
|
|
83
|
+
columns: [
|
|
84
|
+
table.postId,
|
|
85
|
+
table.collectionId
|
|
86
|
+
]
|
|
87
|
+
})
|
|
88
|
+
]);
|
|
89
|
+
// =============================================================================
|
|
90
|
+
// Redirects
|
|
91
|
+
// =============================================================================
|
|
92
|
+
export const redirects = sqliteTable("redirects", {
|
|
93
|
+
id: integer("id").primaryKey({
|
|
94
|
+
autoIncrement: true
|
|
95
|
+
}),
|
|
96
|
+
fromPath: text("from_path").notNull().unique(),
|
|
97
|
+
toPath: text("to_path").notNull(),
|
|
98
|
+
type: integer("type", {
|
|
99
|
+
mode: "number"
|
|
100
|
+
}).notNull().default(301),
|
|
101
|
+
createdAt: integer("created_at").notNull()
|
|
102
|
+
});
|
|
103
|
+
// =============================================================================
|
|
104
|
+
// Settings (Key-Value)
|
|
105
|
+
// =============================================================================
|
|
106
|
+
export const settings = sqliteTable("settings", {
|
|
107
|
+
key: text("key").primaryKey(),
|
|
108
|
+
value: text("value").notNull(),
|
|
109
|
+
updatedAt: integer("updated_at").notNull()
|
|
110
|
+
});
|
|
111
|
+
// =============================================================================
|
|
112
|
+
// better-auth tables
|
|
113
|
+
// Note: Using { mode: "timestamp" } so drizzle auto-converts Date <-> integer
|
|
114
|
+
// =============================================================================
|
|
115
|
+
export const user = sqliteTable("user", {
|
|
116
|
+
id: text("id").primaryKey(),
|
|
117
|
+
name: text("name").notNull(),
|
|
118
|
+
email: text("email").notNull().unique(),
|
|
119
|
+
emailVerified: integer("email_verified", {
|
|
120
|
+
mode: "boolean"
|
|
121
|
+
}).notNull().default(false),
|
|
122
|
+
image: text("image"),
|
|
123
|
+
role: text("role").default("admin"),
|
|
124
|
+
createdAt: integer("created_at", {
|
|
125
|
+
mode: "timestamp"
|
|
126
|
+
}).notNull(),
|
|
127
|
+
updatedAt: integer("updated_at", {
|
|
128
|
+
mode: "timestamp"
|
|
129
|
+
}).notNull()
|
|
130
|
+
});
|
|
131
|
+
export const session = sqliteTable("session", {
|
|
132
|
+
id: text("id").primaryKey(),
|
|
133
|
+
expiresAt: integer("expires_at", {
|
|
134
|
+
mode: "timestamp"
|
|
135
|
+
}).notNull(),
|
|
136
|
+
token: text("token").notNull().unique(),
|
|
137
|
+
createdAt: integer("created_at", {
|
|
138
|
+
mode: "timestamp"
|
|
139
|
+
}).notNull(),
|
|
140
|
+
updatedAt: integer("updated_at", {
|
|
141
|
+
mode: "timestamp"
|
|
142
|
+
}).notNull(),
|
|
143
|
+
ipAddress: text("ip_address"),
|
|
144
|
+
userAgent: text("user_agent"),
|
|
145
|
+
userId: text("user_id").notNull().references(()=>user.id)
|
|
146
|
+
});
|
|
147
|
+
export const account = sqliteTable("account", {
|
|
148
|
+
id: text("id").primaryKey(),
|
|
149
|
+
accountId: text("account_id").notNull(),
|
|
150
|
+
providerId: text("provider_id").notNull(),
|
|
151
|
+
userId: text("user_id").notNull().references(()=>user.id),
|
|
152
|
+
accessToken: text("access_token"),
|
|
153
|
+
refreshToken: text("refresh_token"),
|
|
154
|
+
idToken: text("id_token"),
|
|
155
|
+
accessTokenExpiresAt: integer("access_token_expires_at", {
|
|
156
|
+
mode: "timestamp"
|
|
157
|
+
}),
|
|
158
|
+
refreshTokenExpiresAt: integer("refresh_token_expires_at", {
|
|
159
|
+
mode: "timestamp"
|
|
160
|
+
}),
|
|
161
|
+
scope: text("scope"),
|
|
162
|
+
password: text("password"),
|
|
163
|
+
createdAt: integer("created_at", {
|
|
164
|
+
mode: "timestamp"
|
|
165
|
+
}).notNull(),
|
|
166
|
+
updatedAt: integer("updated_at", {
|
|
167
|
+
mode: "timestamp"
|
|
168
|
+
}).notNull()
|
|
169
|
+
});
|
|
170
|
+
export const verification = sqliteTable("verification", {
|
|
171
|
+
id: text("id").primaryKey(),
|
|
172
|
+
identifier: text("identifier").notNull(),
|
|
173
|
+
value: text("value").notNull(),
|
|
174
|
+
expiresAt: integer("expires_at", {
|
|
175
|
+
mode: "timestamp"
|
|
176
|
+
}).notNull(),
|
|
177
|
+
createdAt: integer("created_at", {
|
|
178
|
+
mode: "timestamp"
|
|
179
|
+
}),
|
|
180
|
+
updatedAt: integer("updated_at", {
|
|
181
|
+
mode: "timestamp"
|
|
182
|
+
})
|
|
183
|
+
});
|
|
@@ -4,14 +4,11 @@
|
|
|
4
4
|
* Simple implementation that just renders children directly.
|
|
5
5
|
* For complex translations with embedded JSX, use the t() function with placeholders.
|
|
6
6
|
*/
|
|
7
|
-
|
|
8
7
|
import type { FC, PropsWithChildren } from "hono/jsx";
|
|
9
|
-
|
|
10
8
|
export interface TransProps extends PropsWithChildren {
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
comment?: string;
|
|
10
|
+
id?: string;
|
|
13
11
|
}
|
|
14
|
-
|
|
15
12
|
/**
|
|
16
13
|
* Trans component - renders children as-is
|
|
17
14
|
* Note: This is a simplified implementation. For translations with embedded JSX,
|
|
@@ -24,8 +21,5 @@ export interface TransProps extends PropsWithChildren {
|
|
|
24
21
|
* </Trans>
|
|
25
22
|
* ```
|
|
26
23
|
*/
|
|
27
|
-
export const Trans: FC<TransProps
|
|
28
|
-
|
|
29
|
-
// For now, we just render children as-is (works for English/default locale)
|
|
30
|
-
return <>{children}</>;
|
|
31
|
-
};
|
|
24
|
+
export declare const Trans: FC<TransProps>;
|
|
25
|
+
//# sourceMappingURL=Trans.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Trans.d.ts","sourceRoot":"","sources":["../../src/i18n/Trans.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,EAAE,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAEtD,MAAM,WAAW,UAAW,SAAQ,iBAAiB;IACnD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,KAAK,EAAE,EAAE,CAAC,UAAU,CAIhC,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Trans Component for Hono JSX
|
|
3
|
+
*
|
|
4
|
+
* Simple implementation that just renders children directly.
|
|
5
|
+
* For complex translations with embedded JSX, use the t() function with placeholders.
|
|
6
|
+
*/ import { jsx as _jsx, Fragment as _Fragment } from "hono/jsx/jsx-runtime";
|
|
7
|
+
/**
|
|
8
|
+
* Trans component - renders children as-is
|
|
9
|
+
* Note: This is a simplified implementation. For translations with embedded JSX,
|
|
10
|
+
* it's recommended to use t() with placeholders instead.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```tsx
|
|
14
|
+
* <Trans comment="@context: Help text">
|
|
15
|
+
* Visit the <a href="/docs">documentation</a>
|
|
16
|
+
* </Trans>
|
|
17
|
+
* ```
|
|
18
|
+
*/ export const Trans = ({ children })=>{
|
|
19
|
+
// In a full implementation, this would extract and translate the content
|
|
20
|
+
// For now, we just render children as-is (works for English/default locale)
|
|
21
|
+
return /*#__PURE__*/ _jsx(_Fragment, {
|
|
22
|
+
children: children
|
|
23
|
+
});
|
|
24
|
+
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hono JSX i18n Context System
|
|
3
|
+
*
|
|
4
|
+
* Mimics React's Context API for Hono JSX to provide i18n without prop drilling
|
|
5
|
+
*/
|
|
6
|
+
import type { Context } from "hono";
|
|
7
|
+
import type { FC, PropsWithChildren } from "hono/jsx";
|
|
8
|
+
import type { I18n } from "@lingui/core";
|
|
9
|
+
/**
|
|
10
|
+
* Message descriptor that accepts both pre-macro (without id) and post-macro (with id) formats
|
|
11
|
+
* This allows TypeScript to accept t({ message, comment }) before macro transformation
|
|
12
|
+
*/
|
|
13
|
+
type TranslationDescriptor = {
|
|
14
|
+
id?: string;
|
|
15
|
+
message: string;
|
|
16
|
+
comment?: string;
|
|
17
|
+
values?: Record<string, any>;
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* I18nProvider - wraps your app to provide i18n context
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```tsx
|
|
24
|
+
* import { I18nProvider } from "@/i18n";
|
|
25
|
+
*
|
|
26
|
+
* return c.html(
|
|
27
|
+
* <I18nProvider c={c}>
|
|
28
|
+
* <YourApp />
|
|
29
|
+
* </I18nProvider>
|
|
30
|
+
* );
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export interface I18nProviderProps extends PropsWithChildren {
|
|
34
|
+
c: Context;
|
|
35
|
+
}
|
|
36
|
+
export declare const I18nProvider: FC<I18nProviderProps>;
|
|
37
|
+
/**
|
|
38
|
+
* useLingui hook - get i18n instance and translation function
|
|
39
|
+
* Mimics @lingui/react's useLingui() API
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```tsx
|
|
43
|
+
* import { t } from "@lingui/core/macro";
|
|
44
|
+
* import { useLingui } from "@/i18n";
|
|
45
|
+
*
|
|
46
|
+
* function MyComponent() {
|
|
47
|
+
* const { t: _ } = useLingui(); // Use _ to avoid conflict with macro
|
|
48
|
+
*
|
|
49
|
+
* return (
|
|
50
|
+
* <div>
|
|
51
|
+
* <h1>{_(t({ message: "Dashboard", comment: "@context: Page title" }))}</h1>
|
|
52
|
+
* </div>
|
|
53
|
+
* );
|
|
54
|
+
* }
|
|
55
|
+
* ```
|
|
56
|
+
*
|
|
57
|
+
* Or use the i18n instance directly:
|
|
58
|
+
* ```tsx
|
|
59
|
+
* const { i18n } = useLingui();
|
|
60
|
+
* i18n._(t({ message: "Dashboard", comment: "@context: Page title" }))
|
|
61
|
+
* ```
|
|
62
|
+
*/
|
|
63
|
+
export declare function useLingui(): {
|
|
64
|
+
i18n: I18n;
|
|
65
|
+
t: (descriptor: TranslationDescriptor) => string;
|
|
66
|
+
_: (descriptor: TranslationDescriptor) => string;
|
|
67
|
+
};
|
|
68
|
+
export {};
|
|
69
|
+
//# sourceMappingURL=context.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/i18n/context.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,KAAK,EAAE,EAAE,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AACtD,OAAO,KAAK,EAAE,IAAI,EAAqB,MAAM,cAAc,CAAC;AAG5D;;;GAGG;AACH,KAAK,qBAAqB,GAAG;IAC3B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAC9B,CAAC;AAKF;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,iBAAkB,SAAQ,iBAAiB;IAC1D,CAAC,EAAE,OAAO,CAAC;CACZ;AAED,eAAO,MAAM,YAAY,EAAE,EAAE,CAAC,iBAAiB,CAM9C,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,SAAS;;oBASQ,qBAAqB;oBAArB,qBAAqB;EAcrD"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hono JSX i18n Context System
|
|
3
|
+
*
|
|
4
|
+
* Mimics React's Context API for Hono JSX to provide i18n without prop drilling
|
|
5
|
+
*/ import { jsx as _jsx, Fragment as _Fragment } from "hono/jsx/jsx-runtime";
|
|
6
|
+
import { getI18n as getI18nFromContext } from "./i18n.js";
|
|
7
|
+
// Store i18n instance during render
|
|
8
|
+
let currentI18n = null;
|
|
9
|
+
export const I18nProvider = ({ c, children })=>{
|
|
10
|
+
// Set current i18n for this render
|
|
11
|
+
// Note: In Hono JSX, rendering is synchronous and single-threaded per request
|
|
12
|
+
// so we can safely set global context without cleanup
|
|
13
|
+
currentI18n = getI18nFromContext(c);
|
|
14
|
+
return /*#__PURE__*/ _jsx(_Fragment, {
|
|
15
|
+
children: children
|
|
16
|
+
});
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* useLingui hook - get i18n instance and translation function
|
|
20
|
+
* Mimics @lingui/react's useLingui() API
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```tsx
|
|
24
|
+
* import { t } from "@lingui/core/macro";
|
|
25
|
+
* import { useLingui } from "@/i18n";
|
|
26
|
+
*
|
|
27
|
+
* function MyComponent() {
|
|
28
|
+
* const { t: _ } = useLingui(); // Use _ to avoid conflict with macro
|
|
29
|
+
*
|
|
30
|
+
* return (
|
|
31
|
+
* <div>
|
|
32
|
+
* <h1>{_(t({ message: "Dashboard", comment: "@context: Page title" }))}</h1>
|
|
33
|
+
* </div>
|
|
34
|
+
* );
|
|
35
|
+
* }
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* Or use the i18n instance directly:
|
|
39
|
+
* ```tsx
|
|
40
|
+
* const { i18n } = useLingui();
|
|
41
|
+
* i18n._(t({ message: "Dashboard", comment: "@context: Page title" }))
|
|
42
|
+
* ```
|
|
43
|
+
*/ export function useLingui() {
|
|
44
|
+
if (!currentI18n) {
|
|
45
|
+
throw new Error("useLingui() called outside of I18nProvider. " + "Make sure your component is wrapped in <I18nProvider c={c}>...</I18nProvider>");
|
|
46
|
+
}
|
|
47
|
+
// Create translation function that accepts both pre-macro and post-macro formats
|
|
48
|
+
const translate = (descriptor)=>{
|
|
49
|
+
// The macro will add the id, or it's already present
|
|
50
|
+
// At runtime, we pass it to i18n._ which handles the descriptor with values
|
|
51
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- currentI18n is checked above
|
|
52
|
+
return currentI18n._(descriptor);
|
|
53
|
+
};
|
|
54
|
+
return {
|
|
55
|
+
i18n: currentI18n,
|
|
56
|
+
// t function - can be used with t macro from @lingui/core/macro
|
|
57
|
+
t: translate,
|
|
58
|
+
// _ is an alias for t (shorter)
|
|
59
|
+
_: translate
|
|
60
|
+
};
|
|
61
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Language Detection Utilities
|
|
3
|
+
*/
|
|
4
|
+
import type { Context } from "hono";
|
|
5
|
+
import { type Locale } from "./locales.js";
|
|
6
|
+
export declare const LANGUAGE_COOKIE_NAME = "lang";
|
|
7
|
+
/**
|
|
8
|
+
* Get display name for a language code
|
|
9
|
+
*/
|
|
10
|
+
export declare function getLanguageDisplayName(locale: Locale): string;
|
|
11
|
+
/**
|
|
12
|
+
* Get all supported languages with display names
|
|
13
|
+
*/
|
|
14
|
+
export declare function getSupportedLanguages(): Array<{
|
|
15
|
+
code: Locale;
|
|
16
|
+
name: string;
|
|
17
|
+
}>;
|
|
18
|
+
/**
|
|
19
|
+
* Check if a language code is valid
|
|
20
|
+
*/
|
|
21
|
+
export declare function isValidLanguage(lang: unknown): lang is Locale;
|
|
22
|
+
/**
|
|
23
|
+
* Parse Accept-Language header and return best matching locale
|
|
24
|
+
*/
|
|
25
|
+
export declare function parseAcceptLanguage(header: string | null): Locale;
|
|
26
|
+
/**
|
|
27
|
+
* Detect user's preferred language from Hono context
|
|
28
|
+
* Priority: Cookie > Accept-Language header > Default
|
|
29
|
+
*/
|
|
30
|
+
export declare function detectLanguage(c: Context): Locale;
|
|
31
|
+
//# sourceMappingURL=detect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../../src/i18n/detect.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AACpC,OAAO,EAAiC,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAE1E,eAAO,MAAM,oBAAoB,SAAS,CAAC;AAE3C;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAO7D;AAED;;GAEG;AACH,wBAAgB,qBAAqB,IAAI,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAK7E;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,MAAM,CAE7D;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAwCjE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,CAYjD"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Language Detection Utilities
|
|
3
|
+
*/ import { locales, baseLocale, isLocale } from "./locales.js";
|
|
4
|
+
export const LANGUAGE_COOKIE_NAME = "lang";
|
|
5
|
+
/**
|
|
6
|
+
* Get display name for a language code
|
|
7
|
+
*/ export function getLanguageDisplayName(locale) {
|
|
8
|
+
const names = {
|
|
9
|
+
en: "English",
|
|
10
|
+
"zh-Hans": "简体中文",
|
|
11
|
+
"zh-Hant": "繁體中文"
|
|
12
|
+
};
|
|
13
|
+
return names[locale];
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Get all supported languages with display names
|
|
17
|
+
*/ export function getSupportedLanguages() {
|
|
18
|
+
return locales.map((code)=>({
|
|
19
|
+
code,
|
|
20
|
+
name: getLanguageDisplayName(code)
|
|
21
|
+
}));
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Check if a language code is valid
|
|
25
|
+
*/ export function isValidLanguage(lang) {
|
|
26
|
+
return isLocale(lang);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Parse Accept-Language header and return best matching locale
|
|
30
|
+
*/ export function parseAcceptLanguage(header) {
|
|
31
|
+
if (!header) return baseLocale;
|
|
32
|
+
// Parse "en-US,en;q=0.9,zh-CN;q=0.8" format
|
|
33
|
+
const languages = header.split(",").map((part)=>{
|
|
34
|
+
const [lang, qPart] = part.trim().split(";");
|
|
35
|
+
const q = qPart ? parseFloat(qPart.replace("q=", "")) : 1;
|
|
36
|
+
return {
|
|
37
|
+
lang: lang?.trim() ?? "",
|
|
38
|
+
q
|
|
39
|
+
};
|
|
40
|
+
}).sort((a, b)=>b.q - a.q);
|
|
41
|
+
for (const { lang } of languages){
|
|
42
|
+
// Direct match
|
|
43
|
+
if (isLocale(lang)) {
|
|
44
|
+
return lang;
|
|
45
|
+
}
|
|
46
|
+
// Map common variants
|
|
47
|
+
const normalized = lang.toLowerCase();
|
|
48
|
+
if (normalized.startsWith("zh-cn") || normalized.startsWith("zh-hans")) {
|
|
49
|
+
return "zh-Hans";
|
|
50
|
+
}
|
|
51
|
+
if (normalized.startsWith("zh-tw") || normalized.startsWith("zh-hk") || normalized.startsWith("zh-hant")) {
|
|
52
|
+
return "zh-Hant";
|
|
53
|
+
}
|
|
54
|
+
if (normalized.startsWith("zh")) {
|
|
55
|
+
return "zh-Hans"; // Default Chinese to Simplified
|
|
56
|
+
}
|
|
57
|
+
if (normalized.startsWith("en")) {
|
|
58
|
+
return "en";
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return baseLocale;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Detect user's preferred language from Hono context
|
|
65
|
+
* Priority: Cookie > Accept-Language header > Default
|
|
66
|
+
*/ export function detectLanguage(c) {
|
|
67
|
+
// 1. Check cookie (using getCookie helper)
|
|
68
|
+
const cookies = c.req.raw.headers.get("Cookie") ?? "";
|
|
69
|
+
const cookieMatch = cookies.match(new RegExp(`${LANGUAGE_COOKIE_NAME}=([^;]+)`));
|
|
70
|
+
const cookieLang = cookieMatch?.[1];
|
|
71
|
+
if (cookieLang && isLocale(cookieLang)) {
|
|
72
|
+
return cookieLang;
|
|
73
|
+
}
|
|
74
|
+
// 2. Check Accept-Language header
|
|
75
|
+
const acceptLang = c.req.header("Accept-Language") ?? null;
|
|
76
|
+
return parseAcceptLanguage(acceptLang);
|
|
77
|
+
}
|
|
@@ -15,37 +15,16 @@
|
|
|
15
15
|
*
|
|
16
16
|
* The msg macro generates hash-based IDs at compile time, which match the compiled catalogs.
|
|
17
17
|
*/
|
|
18
|
-
|
|
19
18
|
import { I18n } from "@lingui/core";
|
|
20
19
|
import { locales, baseLocale, isLocale, type Locale } from "./locales.js";
|
|
21
|
-
import { messages as messagesEn } from "./locales/en.js";
|
|
22
|
-
import { messages as messagesZhHans } from "./locales/zh-Hans.js";
|
|
23
|
-
import { messages as messagesZhHant } from "./locales/zh-Hant.js";
|
|
24
|
-
|
|
25
20
|
export { locales, baseLocale, isLocale, type Locale };
|
|
26
|
-
|
|
27
|
-
// Export I18n type for convenience
|
|
28
21
|
export type { I18n };
|
|
29
|
-
|
|
30
22
|
/**
|
|
31
23
|
* Create a new i18n instance for a specific locale.
|
|
32
24
|
* IMPORTANT: In Cloudflare Workers (concurrent environment), we must create
|
|
33
25
|
* a new instance per request to avoid race conditions. Never use a global instance!
|
|
34
26
|
*/
|
|
35
|
-
export function createI18n(locale: Locale): I18n
|
|
36
|
-
const i18n = new I18n({});
|
|
37
|
-
|
|
38
|
-
// Load all catalogs with English as fallback
|
|
39
|
-
i18n.load("en", messagesEn);
|
|
40
|
-
i18n.load("zh-Hans", { ...messagesEn, ...messagesZhHans });
|
|
41
|
-
i18n.load("zh-Hant", { ...messagesEn, ...messagesZhHant });
|
|
42
|
-
|
|
43
|
-
// Activate locale after loading messages to avoid warnings
|
|
44
|
-
i18n.activate(locale);
|
|
45
|
-
|
|
46
|
-
return i18n;
|
|
47
|
-
}
|
|
48
|
-
|
|
27
|
+
export declare function createI18n(locale: Locale): I18n;
|
|
49
28
|
/**
|
|
50
29
|
* Helper to get the per-request i18n instance from Hono context.
|
|
51
30
|
* Use this in route handlers.
|
|
@@ -57,6 +36,7 @@ export function createI18n(locale: Locale): I18n {
|
|
|
57
36
|
* const i18n = getI18n(c);
|
|
58
37
|
* const title = i18n._(msg({ message: "Dashboard", comment: "@context: Page title" }));
|
|
59
38
|
*/
|
|
60
|
-
export function getI18n(c: {
|
|
61
|
-
|
|
62
|
-
}
|
|
39
|
+
export declare function getI18n(c: {
|
|
40
|
+
get(key: "i18n"): I18n;
|
|
41
|
+
}): I18n;
|
|
42
|
+
//# sourceMappingURL=i18n.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["../../src/i18n/i18n.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,MAAM,EAAE,MAAM,cAAc,CAAC;AAK1E,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,KAAK,MAAM,EAAE,CAAC;AAGtD,YAAY,EAAE,IAAI,EAAE,CAAC;AAErB;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAY/C;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE;IAAE,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GAAG,IAAI,CAE3D"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* i18n Runtime using @lingui/core with Lingui macros
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* import { msg } from "@lingui/core/macro";
|
|
6
|
+
* import { bindI18n } from "@/i18n";
|
|
7
|
+
*
|
|
8
|
+
* const { i18n } = bindI18n(c.get("i18n"));
|
|
9
|
+
*
|
|
10
|
+
* // Simple message
|
|
11
|
+
* i18n._(msg({ message: "Hello", comment: "@context: Greeting" }))
|
|
12
|
+
*
|
|
13
|
+
* // With interpolation
|
|
14
|
+
* i18n._(msg({ message: "Welcome, {name}!", comment: "@context: Welcome" }), { name })
|
|
15
|
+
*
|
|
16
|
+
* The msg macro generates hash-based IDs at compile time, which match the compiled catalogs.
|
|
17
|
+
*/ import { I18n } from "@lingui/core";
|
|
18
|
+
import { locales, baseLocale, isLocale } from "./locales.js";
|
|
19
|
+
import { messages as messagesEn } from "./locales/en.js";
|
|
20
|
+
import { messages as messagesZhHans } from "./locales/zh-Hans.js";
|
|
21
|
+
import { messages as messagesZhHant } from "./locales/zh-Hant.js";
|
|
22
|
+
export { locales, baseLocale, isLocale };
|
|
23
|
+
/**
|
|
24
|
+
* Create a new i18n instance for a specific locale.
|
|
25
|
+
* IMPORTANT: In Cloudflare Workers (concurrent environment), we must create
|
|
26
|
+
* a new instance per request to avoid race conditions. Never use a global instance!
|
|
27
|
+
*/ export function createI18n(locale) {
|
|
28
|
+
const i18n = new I18n({});
|
|
29
|
+
// Load all catalogs with English as fallback
|
|
30
|
+
i18n.load("en", messagesEn);
|
|
31
|
+
i18n.load("zh-Hans", {
|
|
32
|
+
...messagesEn,
|
|
33
|
+
...messagesZhHans
|
|
34
|
+
});
|
|
35
|
+
i18n.load("zh-Hant", {
|
|
36
|
+
...messagesEn,
|
|
37
|
+
...messagesZhHant
|
|
38
|
+
});
|
|
39
|
+
// Activate locale after loading messages to avoid warnings
|
|
40
|
+
i18n.activate(locale);
|
|
41
|
+
return i18n;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Helper to get the per-request i18n instance from Hono context.
|
|
45
|
+
* Use this in route handlers.
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* import { msg } from "@lingui/core/macro";
|
|
49
|
+
* import { getI18n } from "@/i18n";
|
|
50
|
+
*
|
|
51
|
+
* const i18n = getI18n(c);
|
|
52
|
+
* const title = i18n._(msg({ message: "Dashboard", comment: "@context: Page title" }));
|
|
53
|
+
*/ export function getI18n(c) {
|
|
54
|
+
return c.get("i18n");
|
|
55
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* i18n Module
|
|
3
|
+
*
|
|
4
|
+
* IMPORTANT: This module is designed for concurrent environments (Cloudflare Workers).
|
|
5
|
+
* We create a new i18n instance per request to avoid race conditions.
|
|
6
|
+
*
|
|
7
|
+
* This is a custom implementation compatible with Hono JSX (SSR), not React.
|
|
8
|
+
* It provides a React-like API using Lingui macros with a custom context system.
|
|
9
|
+
*
|
|
10
|
+
* Usage:
|
|
11
|
+
* ```tsx
|
|
12
|
+
* import { useLingui, Trans, I18nProvider } from "@/i18n";
|
|
13
|
+
*
|
|
14
|
+
* // Wrap your app in I18nProvider (automatically done by BaseLayout when c is provided)
|
|
15
|
+
* c.html(
|
|
16
|
+
* <I18nProvider c={c}>
|
|
17
|
+
* <MyApp />
|
|
18
|
+
* </I18nProvider>
|
|
19
|
+
* );
|
|
20
|
+
*
|
|
21
|
+
* // Inside components, use useLingui() hook
|
|
22
|
+
* function MyApp() {
|
|
23
|
+
* const { t } = useLingui();
|
|
24
|
+
*
|
|
25
|
+
* return (
|
|
26
|
+
* <div>
|
|
27
|
+
* <h1>{t({ message: "Dashboard", comment: "@context: Page title" })}</h1>
|
|
28
|
+
* <Trans comment="@context: Help text">
|
|
29
|
+
* Read the <a href="/docs">documentation</a>
|
|
30
|
+
* </Trans>
|
|
31
|
+
* </div>
|
|
32
|
+
* );
|
|
33
|
+
* }
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export { createI18n, getI18n, locales, baseLocale, isLocale, type Locale, type I18n, } from "./i18n.js";
|
|
37
|
+
export { I18nProvider, useLingui } from "./context.js";
|
|
38
|
+
export { Trans } from "./Trans.js";
|
|
39
|
+
export { detectLanguage, isValidLanguage, parseAcceptLanguage, getLanguageDisplayName, getSupportedLanguages, LANGUAGE_COOKIE_NAME, } from "./detect.js";
|
|
40
|
+
export { i18nMiddleware } from "./middleware.js";
|
|
41
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/i18n/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAGH,OAAO,EACL,UAAU,EACV,OAAO,EACP,OAAO,EACP,UAAU,EACV,QAAQ,EACR,KAAK,MAAM,EACX,KAAK,IAAI,GACV,MAAM,WAAW,CAAC;AAGnB,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAGvD,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAGnC,OAAO,EACL,cAAc,EACd,eAAe,EACf,mBAAmB,EACnB,sBAAsB,EACtB,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC"}
|