feat: add Traditional Chinese locale support
Adds Traditional Chinese locale support and updates locale-related tests.
This commit is contained in:
parent
6da367a47b
commit
28b1215efa
|
|
@ -1142,7 +1142,11 @@ watch(
|
|||
<SelectContent>
|
||||
<SelectItem v-for="locale in LOCALE_OPTIONS" :key="locale.value" :value="locale.value">
|
||||
<div class="flex items-center gap-2">
|
||||
<span>{{ locale.flag }}</span>
|
||||
<span
|
||||
class="inline-flex h-5 w-6 shrink-0 items-center justify-center text-sm font-medium leading-none"
|
||||
>
|
||||
{{ locale.flag }}
|
||||
</span>
|
||||
<span>{{ locale.label }}</span>
|
||||
</div>
|
||||
</SelectItem>
|
||||
|
|
|
|||
|
|
@ -201,7 +201,12 @@ onBeforeUnmount(close);
|
|||
class="h-3 w-3 shrink-0"
|
||||
:class="[isItemSelected(item) ? selectedCheckClass : 'opacity-0']"
|
||||
/>
|
||||
<span v-if="item.leadingText" class="text-base leading-none">{{ item.leadingText }}</span>
|
||||
<span
|
||||
v-if="item.leadingText"
|
||||
class="inline-flex h-5 w-6 shrink-0 items-center justify-center text-sm font-medium leading-none"
|
||||
>
|
||||
{{ item.leadingText }}
|
||||
</span>
|
||||
<component
|
||||
:is="item.icon"
|
||||
v-if="item.icon"
|
||||
|
|
|
|||
|
|
@ -2,19 +2,20 @@ import { createI18n } from "vue-i18n";
|
|||
import zhCN from "./locales/zh-CN";
|
||||
import { safeLocalStorageGet, safeLocalStorageSet } from "@/lib/safeStorage";
|
||||
|
||||
export type Locale = "en" | "es" | "zh-CN";
|
||||
export type Locale = "en" | "es" | "zh-CN" | "zh-TW";
|
||||
type LocaleMessages = Record<string, unknown>;
|
||||
type I18nGlobal = {
|
||||
locale: { value: Locale };
|
||||
setLocaleMessage: (locale: Locale, messages: LocaleMessages) => void;
|
||||
};
|
||||
|
||||
const supportedLocales: Locale[] = ["en", "es", "zh-CN"];
|
||||
const supportedLocales: Locale[] = ["en", "es", "zh-CN", "zh-TW"];
|
||||
const defaultLocale: Locale = "zh-CN";
|
||||
const loadedLocales = new Set<Locale>([defaultLocale]);
|
||||
const localeLoaders: Record<Exclude<Locale, "zh-CN">, () => Promise<{ default: LocaleMessages }>> = {
|
||||
en: () => import("./locales/en"),
|
||||
es: () => import("./locales/es"),
|
||||
"zh-TW": () => import("./locales/zh-TW"),
|
||||
};
|
||||
|
||||
export function normalizeLocale(value: string | null): Locale | null {
|
||||
|
|
@ -27,8 +28,17 @@ export function normalizeLocale(value: string | null): Locale | null {
|
|||
export function localeFromLanguageTag(value: string | null | undefined): Locale | null {
|
||||
if (!value) return null;
|
||||
const normalized = value.replace("_", "-").toLowerCase();
|
||||
if (normalized === "zh-cn" || normalized.startsWith("zh-")) return "zh-CN";
|
||||
if (normalized === "zh") return "zh-CN";
|
||||
if (normalized === "zh" || normalized.startsWith("zh-")) {
|
||||
if (
|
||||
normalized.includes("hant") ||
|
||||
normalized.startsWith("zh-tw") ||
|
||||
normalized.startsWith("zh-hk") ||
|
||||
normalized.startsWith("zh-mo")
|
||||
) {
|
||||
return "zh-TW";
|
||||
}
|
||||
return "zh-CN";
|
||||
}
|
||||
if (normalized === "en" || normalized.startsWith("en-")) return "en";
|
||||
if (normalized === "es" || normalized.startsWith("es-")) return "es";
|
||||
return null;
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -10,7 +10,7 @@ import type {
|
|||
QueryTab,
|
||||
} from "@/types/database";
|
||||
import * as api from "@/lib/api";
|
||||
import { currentLocale } from "@/i18n";
|
||||
import { currentLocale, type Locale } from "@/i18n";
|
||||
import { aiTableMentionKey, type AiTableMention } from "@/lib/aiTableMentions";
|
||||
import { aiSkillForAction } from "@/lib/aiSkills";
|
||||
import { isSchemaAware } from "@/lib/databaseCapabilities";
|
||||
|
|
@ -18,6 +18,10 @@ import { isSchemaAware } from "@/lib/databaseCapabilities";
|
|||
export type AiAction = "generate" | "explain" | "optimize" | "fix" | "convert" | "sampleData";
|
||||
export type AiAssistantMode = "ask" | "agent";
|
||||
|
||||
function isChineseLocale(locale: Locale): boolean {
|
||||
return locale === "zh-CN" || locale === "zh-TW";
|
||||
}
|
||||
|
||||
export interface AiSchemaTable {
|
||||
schema?: string;
|
||||
name: string;
|
||||
|
|
@ -47,7 +51,7 @@ export interface AiRequestInput {
|
|||
}
|
||||
|
||||
export async function runAiAction(input: AiRequestInput, history?: api.AiMessage[]): Promise<string> {
|
||||
const isZh = currentLocale() === "zh-CN";
|
||||
const isZh = isChineseLocale(currentLocale());
|
||||
const skill = aiSkillForAction(input.action);
|
||||
const systemPrompt = buildSystemPrompt(input.action, input.context, input.mode);
|
||||
const instruction = isZh ? skill.userInstruction.zh : skill.userInstruction.en;
|
||||
|
|
@ -78,7 +82,7 @@ export async function runAiStream(
|
|||
sessionId?: string,
|
||||
onReasoningDelta?: (delta: string) => void,
|
||||
): Promise<void> {
|
||||
const isZh = currentLocale() === "zh-CN";
|
||||
const isZh = isChineseLocale(currentLocale());
|
||||
const skill = aiSkillForAction(input.action);
|
||||
const systemPrompt = buildSystemPrompt(input.action, input.context, input.mode);
|
||||
const instruction = isZh ? skill.userInstruction.zh : skill.userInstruction.en;
|
||||
|
|
@ -136,7 +140,7 @@ export function buildSystemPrompt(action: AiAction, context: AiContext, mode: Ai
|
|||
const resultPreview = context.lastResultPreview ? `\nLast result preview:\n${context.lastResultPreview}\n` : "";
|
||||
const lastError = context.lastError ? `\nLast error:\n${context.lastError}\n` : "";
|
||||
|
||||
const isZh = currentLocale() === "zh-CN";
|
||||
const isZh = isChineseLocale(currentLocale());
|
||||
|
||||
const lines: string[] = [
|
||||
...buildBasePromptLines(isZh),
|
||||
|
|
|
|||
|
|
@ -4,4 +4,5 @@ export const LOCALE_OPTIONS: { value: Locale; flag: string; label: string }[] =
|
|||
{ value: "en", flag: "🇺🇸", label: "English" },
|
||||
{ value: "es", flag: "🇪🇸", label: "Español" },
|
||||
{ value: "zh-CN", flag: "🇨🇳", label: "简体中文" },
|
||||
{ value: "zh-TW", flag: "繁", label: "繁體中文" },
|
||||
];
|
||||
|
|
|
|||
|
|
@ -22,8 +22,11 @@ class MemoryStorage {
|
|||
}
|
||||
}
|
||||
|
||||
const localStorage = new MemoryStorage();
|
||||
localStorage.setItem("dbx-locale", "zh-CN");
|
||||
|
||||
Object.defineProperty(globalThis, "localStorage", {
|
||||
value: new MemoryStorage(),
|
||||
value: localStorage,
|
||||
configurable: true,
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -22,8 +22,11 @@ class MemoryStorage {
|
|||
}
|
||||
}
|
||||
|
||||
const localStorage = new MemoryStorage();
|
||||
localStorage.setItem("dbx-locale", "zh-CN");
|
||||
|
||||
Object.defineProperty(globalThis, "localStorage", {
|
||||
value: new MemoryStorage(),
|
||||
value: localStorage,
|
||||
configurable: true,
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -10,13 +10,15 @@ test("normalizes exact supported locales", () => {
|
|||
assert.equal(normalizeLocale("en"), "en");
|
||||
assert.equal(normalizeLocale("es"), "es");
|
||||
assert.equal(normalizeLocale("zh-CN"), "zh-CN");
|
||||
assert.equal(normalizeLocale("zh-TW"), "zh-TW");
|
||||
assert.equal(normalizeLocale("fr-FR"), null);
|
||||
assert.equal(normalizeLocale(null), null);
|
||||
});
|
||||
|
||||
test("maps user language tags to supported locales", () => {
|
||||
assert.equal(localeFromLanguageTag("zh-Hans-CN"), "zh-CN");
|
||||
assert.equal(localeFromLanguageTag("zh_TW"), "zh-CN");
|
||||
assert.equal(localeFromLanguageTag("zh_TW"), "zh-TW");
|
||||
assert.equal(localeFromLanguageTag("zh-Hant-HK"), "zh-TW");
|
||||
assert.equal(localeFromLanguageTag("en-US"), "en");
|
||||
assert.equal(localeFromLanguageTag("es-MX"), "es");
|
||||
assert.equal(localeFromLanguageTag("fr-FR"), null);
|
||||
|
|
|
|||
Loading…
Reference in New Issue