mirror of
https://github.com/jakejarvis/sofa.git
synced 2026-07-14 18:15:56 -04:00
* feat: add i18n with LingUI, Crowdin integration, and typed error codes - Add `@sofa/i18n` shared package with LingUI v5 (v6-ready config using `defineConfig` + `@lingui/format-po`), eager English + lazy-loaded fr/de/es/it/pt catalogs, `Intl`-based date/number format utilities, and test helpers - Wire `@lingui/vite-plugin` + babel macro plugin for web, and `@lingui/metro-transformer` + babel config for native - Add `I18nProvider` to both app roots with locale auto-detection (navigator.language / expo-localization) and persistence (localStorage / MMKV) - Wrap all ~512 user-facing strings across web and native with LingUI macros (`<Trans>`, `useLingui`/`t`, `i18n._(msg`...`)`, `plural`) - Add language switcher to Settings in both apps - Add `@sofa/api/errors` with 13 typed `AppErrorCode` values and `appErrorData()` helper for contract `.errors()` schemas - Update all oRPC contract error definitions with typed `data` fields; convert import procedure `throw new Error()` to `ORPCError` with codes - Add per-app `error-messages.ts` utilities that map error codes to localized strings; update global `QueryCache.onError` handlers to stop leaking raw `error.message` to users - Add `crowdin.yml` config and `.github/workflows/crowdin.yml` for automated source upload on merge and translation pull via dispatch - Add `lingui.config.ts` at repo root with `bun run i18n:extract` and `bun run i18n:compile` convenience scripts Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore: add Crowdin language mapping and ignore context file * fix(i18n): address 20 localization quality issues - Stop leaking raw error.message to users in change-password and account-section; use localized fallbacks instead - Add typed error data to discover contract's .errors() schema - Replace all manual English plural suffixes with LingUI plural() macro in episode counts, backup counts, star ratings, title/image counts - Replace date-fns formatDistanceToNow and hardcoded date patterns with locale-aware formatDate/formatRelativeTime from @sofa/i18n/format - Convert integration-configs from module-scope translations (frozen at import time) to lazy getIntegrationConfigs(i18n) function - Combine split Trans fragments into single translatable units in backup-schedule retention sentence and stats-display period labels - Localize TV media type badge and full episode accessibilityLabel - Replace Android-incompatible Alert.alert language picker (max 3 buttons) with zeego DropdownMenu - Await async locale initialization before hiding splash screen so non-English users don't see English flash on cold start - Add @lingui/core as direct native app dependency Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(i18n): add Intl polyfills for Hermes, replace DropdownMenu language picker, and remove date-fns - Add `@formatjs/intl-*` polyfills loaded at app startup in `intl-polyfills.ts` so Hermes on Android has full `Intl` support for locale-aware formatting - Alias `@formatjs/icu-messageformat-parser` to its `no-parser` variant in metro config to reduce bundle size - Replace the zeego `DropdownMenu` language picker in Settings with a new `SelectModal` component that works reliably on all platforms without the Android 3-button limit - Replace `date-fns` `format`/`parseISO` in `person/[id].tsx` with `formatDate` from `@sofa/i18n/format`; remove `date-fns` from native and web `package.json` - Refactor `StatusActionButton` to use a `StatusLabel` component with `<Trans>` rather than a `getStatusConfig(t)` factory so labels are always reactive to locale changes - Fix crowdin workflow to use root `bun run i18n:compile` script instead of `cd packages/i18n && bun run compile` - Wrap root layout `GestureHandlerRootView` in `SafeAreaProvider` and add `.catch` to locale-ready promise to prevent unhandled rejections blocking the splash screen * fix(i18n): localize integration status helpers, fix stats-display Trans wrapping, and clean up SelectModal - Localize `webhookStatus` and `listStatus` in `integration-card.tsx` using `i18n._(msg`...`)` so status strings are translated instead of always rendering in English - Wrap "Movies {select}" and "Episodes {select}" in a single `<Trans>` in `stats-display.tsx` so the period selector element is embedded inside the translatable unit rather than concatenated outside it - Fix locale activation order in Settings: close the modal first, then `activateLocale`, and only call `setPersistedLocale` on success to avoid persisting a locale that failed to load - Remove the redundant `SafeAreaProvider`/`SafeAreaView` wrapper from `SelectModal` — the root layout already provides `SafeAreaProvider` - Recompile all six `.po`/`.ts` catalogs to pick up new and updated message strings * chore(i18n): crowdin sync --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
95 lines
2.4 KiB
JSON
95 lines
2.4 KiB
JSON
{
|
|
"$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
|
|
"vcs": {
|
|
"enabled": true,
|
|
"clientKind": "git",
|
|
"useIgnoreFile": true
|
|
},
|
|
"files": {
|
|
"ignoreUnknown": true,
|
|
"includes": [
|
|
"**",
|
|
"!node_modules",
|
|
"!dist",
|
|
"!build",
|
|
"!packages/db/drizzle",
|
|
"!packages/i18n/src/po/*.ts",
|
|
"!packages/tmdb/src/schema.d.ts",
|
|
"!**/routeTree.gen.ts",
|
|
"!apps/native/.expo/types/**/*.ts",
|
|
"!apps/native/expo-env.d.ts",
|
|
"!apps/native/uniwind-types.d.ts",
|
|
"!docs"
|
|
]
|
|
},
|
|
"css": {
|
|
"parser": {
|
|
"cssModules": true,
|
|
"tailwindDirectives": true
|
|
}
|
|
},
|
|
"formatter": {
|
|
"enabled": true,
|
|
"indentStyle": "space",
|
|
"indentWidth": 2
|
|
},
|
|
"linter": {
|
|
"enabled": true,
|
|
"domains": {
|
|
"react": "recommended"
|
|
},
|
|
"rules": {
|
|
"recommended": true,
|
|
"suspicious": {
|
|
"noUnknownAtRules": "off"
|
|
},
|
|
"nursery": {
|
|
"useSortedClasses": {
|
|
"level": "error",
|
|
"options": {
|
|
"attributes": [
|
|
"class",
|
|
"classList",
|
|
"className",
|
|
"headerClassName",
|
|
"contentContainerClassName",
|
|
"columnWrapperClassName",
|
|
"endFillColorClassName",
|
|
"imageClassName",
|
|
"tintColorClassName",
|
|
"ios_backgroundColorClassName",
|
|
"thumbColorClassName",
|
|
"trackColorOnClassName",
|
|
"trackColorOffClassName",
|
|
"selectionColorClassName",
|
|
"cursorColorClassName",
|
|
"underlineColorAndroidClassName",
|
|
"placeholderTextColorClassName",
|
|
"selectionHandleColorClassName",
|
|
"colorsClassName",
|
|
"progressBackgroundColorClassName",
|
|
"titleColorClassName",
|
|
"underlayColorClassName",
|
|
"colorClassName",
|
|
"backdropColorClassName",
|
|
"backgroundColorClassName",
|
|
"statusBarBackgroundColorClassName",
|
|
"drawerBackgroundColorClassName",
|
|
"ListFooterComponentClassName",
|
|
"ListHeaderComponentClassName"
|
|
],
|
|
"functions": ["cn", "clsx", "cva", "useResolveClassNames"]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
},
|
|
"assist": {
|
|
"actions": {
|
|
"source": {
|
|
"organizeImports": "on"
|
|
}
|
|
}
|
|
}
|
|
}
|