Files
maternal-app/maternal-web/lib/utils/unitConversion.ts
Andrei c1e37d30b0
Some checks failed
CI/CD Pipeline / Lint and Test (push) Has been cancelled
CI/CD Pipeline / E2E Tests (push) Has been cancelled
CI/CD Pipeline / Build Application (push) Has been cancelled
feat: Implement frontend localization with i18n and measurement units
Implemented comprehensive frontend localization infrastructure supporting
5 languages (English, Spanish, French, Portuguese, Chinese) with measurement
unit preferences (Metric/Imperial). This lays the foundation for international
user support.

**Core Infrastructure:**
- Installed i18next, react-i18next, i18next-browser-languagedetector
- Created I18nProvider component integrated into app layout
- Configured i18next with language detection and localStorage persistence
- Created 35 translation files (5 languages × 7 namespaces)

**Translation Namespaces:**
- common: App-wide UI elements, navigation, actions
- tracking: Activity tracking (feeding, sleep, diaper, milestones)
- ai: AI assistant chat interface
- auth: Authentication flows (login, signup, password reset)
- settings: Settings and preferences
- onboarding: Onboarding flow
- errors: Error messages and validation

**Custom Hooks:**
- useTranslation: Type-safe translation wrapper
- useLocale: Language and measurement system management
- useFormatting: Date, time, number, and unit formatting

**Measurement Unit Support:**
- Created unit conversion utilities (weight, height, temperature, volume)
- Metric: kg, cm, °C, ml
- Imperial: lb, in, °F, oz
- Bidirectional conversion functions

**UI Components:**
- LanguageSelector: Dropdown to change app language
- MeasurementUnitSelector: Toggle between Metric/Imperial
- Integrated both into Settings page Preferences section

**Next Steps (Remaining):**
- Add measurement preferences to backend user schema
- Create onboarding flow with language/measurement selection
- Apply translations to existing components (dashboard, tracking forms)
- Implement multi-language AI responses
- Add professional translations (currently using basic translations)

**File Highlights:**
- lib/i18n/config.ts: i18next configuration
- hooks/useFormatting.ts: Formatting utilities with locale support
- lib/utils/unitConversion.ts: Unit conversion logic
- components/settings/*Selector.tsx: Language and measurement selectors
- locales/*/: Translation files for 5 languages

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-03 10:52:38 +00:00

185 lines
3.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { MeasurementSystem } from '@/hooks/useLocale';
export interface ConvertedValue {
value: number;
unit: string;
}
/**
* Convert weight from kilograms to the preferred measurement system
*/
export function convertWeight(
valueInKg: number,
system: MeasurementSystem
): ConvertedValue {
if (system === 'imperial') {
// Convert kg to lbs (1 kg = 2.20462 lbs)
return {
value: valueInKg * 2.20462,
unit: 'lb',
};
}
return {
value: valueInKg,
unit: 'kg',
};
}
/**
* Convert weight to kilograms from the preferred measurement system
*/
export function convertWeightToKg(
value: number,
system: MeasurementSystem
): number {
if (system === 'imperial') {
// Convert lbs to kg
return value / 2.20462;
}
return value;
}
/**
* Convert height from centimeters to the preferred measurement system
*/
export function convertHeight(
valueInCm: number,
system: MeasurementSystem
): ConvertedValue {
if (system === 'imperial') {
// Convert cm to inches (1 cm = 0.393701 inches)
const inches = valueInCm * 0.393701;
return {
value: inches,
unit: 'in',
};
}
return {
value: valueInCm,
unit: 'cm',
};
}
/**
* Convert height to centimeters from the preferred measurement system
*/
export function convertHeightToCm(
value: number,
system: MeasurementSystem
): number {
if (system === 'imperial') {
// Convert inches to cm
return value / 0.393701;
}
return value;
}
/**
* Convert temperature from Celsius to the preferred measurement system
*/
export function convertTemperature(
valueInCelsius: number,
system: MeasurementSystem
): ConvertedValue {
if (system === 'imperial') {
// Convert Celsius to Fahrenheit: F = (C × 9/5) + 32
return {
value: (valueInCelsius * 9) / 5 + 32,
unit: '°F',
};
}
return {
value: valueInCelsius,
unit: '°C',
};
}
/**
* Convert temperature to Celsius from the preferred measurement system
*/
export function convertTemperatureToCelsius(
value: number,
system: MeasurementSystem
): number {
if (system === 'imperial') {
// Convert Fahrenheit to Celsius: C = (F - 32) × 5/9
return ((value - 32) * 5) / 9;
}
return value;
}
/**
* Convert volume from milliliters to the preferred measurement system
*/
export function convertVolume(
valueInMl: number,
system: MeasurementSystem
): ConvertedValue {
if (system === 'imperial') {
// Convert ml to oz (1 oz = 29.5735 ml)
return {
value: valueInMl / 29.5735,
unit: 'oz',
};
}
return {
value: valueInMl,
unit: 'ml',
};
}
/**
* Convert volume to milliliters from the preferred measurement system
*/
export function convertVolumeToMl(
value: number,
system: MeasurementSystem
): number {
if (system === 'imperial') {
// Convert oz to ml
return value * 29.5735;
}
return value;
}
/**
* Get the unit symbol for a measurement type
*/
export function getUnitSymbol(
type: 'weight' | 'height' | 'temperature' | 'volume',
system: MeasurementSystem
): string {
const units = {
metric: {
weight: 'kg',
height: 'cm',
temperature: '°C',
volume: 'ml',
},
imperial: {
weight: 'lb',
height: 'in',
temperature: '°F',
volume: 'oz',
},
};
return units[system][type];
}
/**
* Get conversion factor for a measurement type
*/
export function getConversionFactor(
type: 'weight' | 'height' | 'temperature' | 'volume'
): { toImperial: number; toMetric: number } {
const factors = {
weight: { toImperial: 2.20462, toMetric: 1 / 2.20462 },
height: { toImperial: 0.393701, toMetric: 1 / 0.393701 },
temperature: { toImperial: 1, toMetric: 1 }, // Temperature uses formula, not factor
volume: { toImperial: 1 / 29.5735, toMetric: 29.5735 },
};
return factors[type];
}