feat(i18n): extract remaining screens into en/zh-Hans catalogs; full Simplified Chinese coverage (closes #68) (#103)
Extends the i18n infra from #97 (Settings screen only) to the rest of the app: session chat screen, connection add/edit/list screens, sessions list (incl. directory grouping from #96), navigation titles, notifications category metadata, error boundary, telemetry consent modal, auth gate, and every chat UI component (permission/question prompts, status indicator, model/variant pickers, directory switcher/browser, reasoning block, tool call card, session info). - 244 new keys added to en.json/zh-Hans.json with reviewed, natural Simplified Chinese (not machine-garbage), keeping key sets identical. - User content, server URLs, code snippets, log/error-detail text, and diagnostics-classify.ts (pure dependency-free module feeding Sentry/ support reports) are intentionally left untranslated per scope. - Interpolation used for counts/names (e.g. reconnect attempt, files count, connection name in delete confirmations); categoryMeta/ CONNECTION_TYPES switched to labelKey indirection since they're module-level constants evaluated before i18next is guaranteed ready. - Added src/lib/i18n/catalog-parity.test.ts (node --test) asserting en.json/zh-Hans.json expose identical key sets and no empty values, to catch future locale drift. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { View, Text, TouchableOpacity, StyleSheet } from "react-native"
|
||||
import { Ionicons } from "@expo/vector-icons"
|
||||
import BottomSheet, { BottomSheetBackdrop, BottomSheetFlatList } from "@gorhom/bottom-sheet"
|
||||
import { useTranslation } from "react-i18next"
|
||||
|
||||
interface VariantOption {
|
||||
id: string | null
|
||||
@@ -16,25 +17,26 @@ interface Props {
|
||||
sheetRef: React.RefObject<BottomSheet | null>
|
||||
}
|
||||
|
||||
const AUTO_OPTION: VariantOption = {
|
||||
id: null,
|
||||
label: "Auto",
|
||||
description: "Use model default reasoning",
|
||||
}
|
||||
|
||||
const EFFORT_DESCRIPTIONS: Record<string, string> = {
|
||||
low: "Faster, less thorough reasoning",
|
||||
medium: "Balanced reasoning and speed",
|
||||
high: "Deep, thorough reasoning",
|
||||
}
|
||||
|
||||
export function VariantPicker({ variants, selected, isDark, onSelect, sheetRef }: Props) {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const effortDescriptions: Record<string, string> = {
|
||||
low: t("chat.variantPicker.effort.low"),
|
||||
medium: t("chat.variantPicker.effort.medium"),
|
||||
high: t("chat.variantPicker.effort.high"),
|
||||
}
|
||||
const autoOption: VariantOption = {
|
||||
id: null,
|
||||
label: t("chat.variantPicker.autoLabel"),
|
||||
description: t("chat.variantPicker.autoDescription"),
|
||||
}
|
||||
|
||||
const options: VariantOption[] = [
|
||||
AUTO_OPTION,
|
||||
autoOption,
|
||||
...Object.keys(variants || {}).map((id) => ({
|
||||
id,
|
||||
label: id.charAt(0).toUpperCase() + id.slice(1),
|
||||
description: EFFORT_DESCRIPTIONS[id] ?? id,
|
||||
description: effortDescriptions[id] ?? id,
|
||||
})),
|
||||
]
|
||||
|
||||
@@ -56,7 +58,7 @@ export function VariantPicker({ variants, selected, isDark, onSelect, sheetRef }
|
||||
)}
|
||||
>
|
||||
<View style={s.header}>
|
||||
<Text style={[s.title, isDark && s.textWhite]}>Reasoning Effort</Text>
|
||||
<Text style={[s.title, isDark && s.textWhite]}>{t("chat.variantPicker.title")}</Text>
|
||||
</View>
|
||||
<BottomSheetFlatList
|
||||
data={options}
|
||||
|
||||
Reference in New Issue
Block a user