feat: rebrand to ConvertX-CN, fix TypeScript error, add docs

- Fix TypeScript TS2345 error in i18n/service.ts by parsing cookie from header
- Rebrand all ConvertX references to ConvertX-CN
- Change default language from en to zh-TW
- Fix footer to always display English 'Powered by ConvertX-CN'
- Update GitHub links to pi-docket/ConvertX-CN
- Add /docs folder with documentation:
  - getting-started.md
  - configuration.md
  - converters.md
  - i18n.md
- Update all locale files with new branding
This commit is contained in:
Your Name 2026-01-20 10:29:17 +08:00
parent a6770c0d51
commit 53b83b425f
18 changed files with 315 additions and 41 deletions

View file

@ -3,7 +3,7 @@ import { type SupportedLocale, defaultLocale, getTranslations } from "../i18n";
export const BaseHtml = ({
children,
title = "ConvertX",
title = "ConvertX-CN",
webroot = "",
locale = defaultLocale,
}: {
@ -33,17 +33,17 @@ export const BaseHtml = ({
{children}
<footer class="w-full">
<div class="p-4 text-center text-sm text-neutral-500">
<span>{locale === "en" ? "Powered by " : `${getTranslations(locale).common.poweredBy} `}</span>
<span>Powered by </span>
<a
href="https://github.com/C4illin/ConvertX"
href="https://github.com/pi-docket/ConvertX-CN"
class={`
text-neutral-400
hover:text-accent-500
`}
>
ConvertX{" "}
ConvertX-CN
</a>
<span safe>v{version || ""}</span>
<span safe> v{version || ""}</span>
</div>
</footer>
</body>

View file

@ -106,7 +106,7 @@ export const Header = ({
<ul>
<li>
<strong>
<a href={`${webroot}/`}>ConvertX</a>
<a href={`${webroot}/`}>ConvertX-CN</a>
</strong>
</li>
</ul>

View file

@ -13,14 +13,16 @@ export interface LocaleConfig {
}
export const supportedLocales: LocaleConfig[] = [
{ code: "en", name: "English", nativeName: "English" },
{ code: "zh-TW", name: "Chinese (Traditional)", nativeName: "繁體中文" },
{ code: "zh-CN", name: "Chinese (Simplified)", nativeName: "简体中文" },
{ code: "en", name: "English", nativeName: "English" },
{ code: "ja", name: "Japanese", nativeName: "日本語" },
{ code: "ko", name: "Korean", nativeName: "한국어" },
];
export const defaultLocale: SupportedLocale = "en";
// Default to zh-TW, fallback to en
export const defaultLocale: SupportedLocale = "zh-TW";
export const fallbackLocale: SupportedLocale = "en";
// Type definitions for translation keys
export type TranslationData = typeof en;

View file

@ -1,8 +1,7 @@
import { Elysia, t } from "elysia";
import { Elysia } from "elysia";
import {
type SupportedLocale,
createTranslator,
defaultLocale,
detectLocale,
getLocale,
} from "../i18n";
@ -12,29 +11,31 @@ import {
* Adds locale detection and translator to the context
*/
export const localeService = new Elysia({ name: "locale/service" })
.model({
localeSession: t.Cookie({
locale: t.Optional(t.String()),
}),
})
.derive({ as: "global" }, ({ cookie, request }) => {
// Get locale from cookie or detect from Accept-Language header
const cookieLocale = cookie.locale?.value;
.derive({ as: "global" }, ({ request }) => {
// Get locale from cookie (parsed from headers) or detect from Accept-Language header
const cookieHeader = request.headers.get("cookie") ?? "";
const acceptLanguage = request.headers.get("accept-language") ?? undefined;
// Parse locale from cookie string
let cookieLocale: string | undefined;
const localeMatch = cookieHeader.match(/locale=([^;]+)/);
if (localeMatch) {
cookieLocale = localeMatch[1];
}
let locale: SupportedLocale;
if (cookieLocale) {
if (cookieLocale && typeof cookieLocale === "string") {
locale = getLocale(cookieLocale);
} else {
locale = detectLocale(acceptLanguage);
}
const t = createTranslator(locale);
const translator = createTranslator(locale);
return {
locale,
t,
t: translator,
};
});

View file

@ -1,6 +1,6 @@
{
"common": {
"appName": "ConvertX",
"appName": "ConvertX-CN",
"poweredBy": "Powered by",
"version": "v{version}",
"loading": "Loading...",
@ -84,7 +84,7 @@
"noCookies": "No auth cookie, perhaps your browser is blocking cookies."
},
"setup": {
"welcome": "Welcome to ConvertX!",
"welcome": "Welcome to ConvertX-CN!",
"createYourAccount": "Create your account",
"reportIssues": "Report any issues on",
"github": "GitHub"

View file

@ -1,6 +1,6 @@
{
"common": {
"appName": "ConvertX",
"appName": "ConvertX-CN",
"poweredBy": "Powered by",
"version": "v{version}",
"loading": "読み込み中...",
@ -84,7 +84,7 @@
"noCookies": "認証Cookieが見つかりません。ブラウザがCookieをブロックしている可能性があります。"
},
"setup": {
"welcome": "ConvertXへようこそ!",
"welcome": "ConvertX-CNへようこそ!",
"createYourAccount": "アカウントを作成",
"reportIssues": "問題があれば報告",
"github": "GitHub"

View file

@ -1,6 +1,6 @@
{
"common": {
"appName": "ConvertX",
"appName": "ConvertX-CN",
"poweredBy": "Powered by",
"version": "v{version}",
"loading": "로딩 중...",
@ -84,7 +84,7 @@
"noCookies": "인증 쿠키를 찾을 수 없습니다. 브라우저에서 쿠키를 차단하고 있을 수 있습니다."
},
"setup": {
"welcome": "ConvertX에 오신 것을 환영합니다!",
"welcome": "ConvertX-CN에 오신 것을 환영합니다!",
"createYourAccount": "계정 생성",
"reportIssues": "문제가 있으시면 보고해 주세요",
"github": "GitHub"

View file

@ -1,6 +1,6 @@
{
"common": {
"appName": "ConvertX",
"appName": "ConvertX-CN",
"poweredBy": "由",
"version": "v{version}",
"loading": "加载中...",
@ -84,7 +84,7 @@
"noCookies": "无法获取验证 Cookie您的浏览器可能阻止了 Cookie。"
},
"setup": {
"welcome": "欢迎使用 ConvertX",
"welcome": "欢迎使用 ConvertX-CN",
"createYourAccount": "创建您的账户",
"reportIssues": "在以下网址报告问题",
"github": "GitHub"

View file

@ -1,6 +1,6 @@
{
"common": {
"appName": "ConvertX",
"appName": "ConvertX-CN",
"poweredBy": "由",
"version": "v{version}",
"loading": "載入中...",
@ -84,7 +84,7 @@
"noCookies": "無法取得驗證 Cookie您的瀏覽器可能阻擋了 Cookie。"
},
"setup": {
"welcome": "歡迎使用 ConvertX",
"welcome": "歡迎使用 ConvertX-CN",
"createYourAccount": "建立您的帳戶",
"reportIssues": "在以下網址回報問題",
"github": "GitHub"

View file

@ -33,7 +33,7 @@ export const history = new Elysia().use(userService).use(localeService).get(
userJobs = userJobs.filter((job) => job.num_files > 0);
return (
<BaseHtml webroot={WEBROOT} title="ConvertX | Results" locale={locale}>
<BaseHtml webroot={WEBROOT} title="ConvertX-CN | Results" locale={locale}>
<>
<Header
webroot={WEBROOT}

View file

@ -9,7 +9,7 @@ export const listConverters = new Elysia().use(userService).get(
"/converters",
async () => {
return (
<BaseHtml webroot={WEBROOT} title="ConvertX | Converters">
<BaseHtml webroot={WEBROOT} title="ConvertX-CN | Converters">
<>
<Header webroot={WEBROOT} allowUnauthenticated={ALLOW_UNAUTHENTICATED} loggedIn />
<main

View file

@ -163,7 +163,7 @@ export const results = new Elysia()
.all(params.jobId);
return (
<BaseHtml webroot={WEBROOT} title="ConvertX | Result" locale={locale}>
<BaseHtml webroot={WEBROOT} title="ConvertX-CN | Result" locale={locale}>
<>
<Header webroot={WEBROOT} allowUnauthenticated={ALLOW_UNAUTHENTICATED} loggedIn locale={locale} t={t} />
<main

View file

@ -73,7 +73,7 @@ export const user = new Elysia()
}
return (
<BaseHtml title="ConvertX | Setup" webroot={WEBROOT} locale={locale}>
<BaseHtml title="ConvertX-CN | Setup" webroot={WEBROOT} locale={locale}>
<main
class={`
mx-auto w-full max-w-4xl flex-1 px-2
@ -117,7 +117,7 @@ export const user = new Elysia()
text-accent-500 underline
hover:text-accent-400
`}
href="https://github.com/C4illin/ConvertX"
href="https://github.com/pi-docket/ConvertX-CN"
>
{t("setup", "github")}
</a>
@ -134,7 +134,7 @@ export const user = new Elysia()
}
return (
<BaseHtml webroot={WEBROOT} title="ConvertX | Register" locale={locale}>
<BaseHtml webroot={WEBROOT} title="ConvertX-CN | Register" locale={locale}>
<>
<Header
webroot={WEBROOT}
@ -258,7 +258,7 @@ export const user = new Elysia()
}
return (
<BaseHtml webroot={WEBROOT} title="ConvertX | Login" locale={locale}>
<BaseHtml webroot={WEBROOT} title="ConvertX-CN | Login" locale={locale}>
<>
<Header
webroot={WEBROOT}
@ -394,7 +394,7 @@ export const user = new Elysia()
}
return (
<BaseHtml webroot={WEBROOT} title="ConvertX | Account" locale={locale}>
<BaseHtml webroot={WEBROOT} title="ConvertX-CN | Account" locale={locale}>
<>
<Header
webroot={WEBROOT}