Leon 2 jaren geleden
bovenliggende
commit
0f3bb1d469
31 gewijzigde bestanden met toevoegingen van 710 en 500 verwijderingen
  1. 2 2
      ios/hola.xcodeproj/project.pbxproj
  2. 0 0
      ios/main.jsbundle
  3. 9 8
      src/components/input/LimitPickers.tsx
  4. 0 276
      src/components/input/LimitPickers_backup.tsx
  5. 1 1
      src/components/input/PickerViews.tsx
  6. 0 11
      src/components/layout/Modal.weapp.tsx
  7. 350 73
      src/context/locales/en.js
  8. 1 1
      src/context/locales/index.ts
  9. 11 1
      src/context/locales/zh.js
  10. 1 1
      src/features/food/FoodTimelineItem.tsx
  11. 3 3
      src/features/trackSomething/components/ActivityHistory.tsx
  12. 2 2
      src/features/trackSomething/components/MetricHistory.tsx
  13. 20 0
      src/features/trackSomething/components/MetricModalAdd.scss
  14. 4 4
      src/features/trackSomething/components/MetricModalAdd.tsx
  15. 1 1
      src/features/trackSomething/components/MetricModalChoose.tsx
  16. 1 1
      src/features/trackSomething/components/MetricModalChoose_backup.tsx
  17. 2 2
      src/features/trackSomething/components/MetricModalOrder.tsx
  18. 66 14
      src/features/trackTimeDuration/components/ChooseScenario.tsx
  19. 11 6
      src/features/trackTimeDuration/components/Clock.tsx
  20. 12 9
      src/features/trackTimeDuration/components/Console.tsx
  21. 8 8
      src/features/trackTimeDuration/components/Rings.rn.tsx
  22. 5 6
      src/features/trackTimeDuration/components/SetSchedule.rn.tsx
  23. 1 1
      src/features/trackTimeDuration/components/SetSchedule.weapp.tsx
  24. 10 8
      src/features/trackTimeDuration/components/StatusIndicator.tsx
  25. 3 2
      src/features/trackTimeDuration/components/TitleView.tsx
  26. 3 3
      src/features/trackTimeDuration/hooks/Console.tsx
  27. 16 12
      src/features/trackTimeDuration/hooks/RingData.tsx
  28. 1 1
      src/pages/account/ProfileSetting.tsx
  29. 47 6
      src/pages/clock/Clock.weapp.tsx
  30. 2 0
      src/store/time.tsx
  31. 117 37
      src/utils/time_format.ts

+ 2 - 2
ios/hola.xcodeproj/project.pbxproj

@@ -550,7 +550,7 @@
 				CODE_SIGN_ENTITLEMENTS = hola/hola.entitlements;
 				CODE_SIGN_IDENTITY = "Apple Development";
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 10;
+				CURRENT_PROJECT_VERSION = 12;
 				DEVELOPMENT_TEAM = GPMXAZ9G5N;
 				ENABLE_BITCODE = NO;
 				INFOPLIST_FILE = hola/Info.plist;
@@ -583,7 +583,7 @@
 				CODE_SIGN_ENTITLEMENTS = hola/hola.entitlements;
 				CODE_SIGN_IDENTITY = "Apple Development";
 				CODE_SIGN_STYLE = Automatic;
-				CURRENT_PROJECT_VERSION = 10;
+				CURRENT_PROJECT_VERSION = 12;
 				DEVELOPMENT_TEAM = GPMXAZ9G5N;
 				INFOPLIST_FILE = hola/Info.plist;
 				LD_RUNPATH_SEARCH_PATHS = (

File diff suppressed because it is too large
+ 0 - 0
ios/main.jsbundle


+ 9 - 8
src/components/input/LimitPickers.tsx

@@ -4,6 +4,7 @@ import './LimitPickers.scss'
 import Taro from "@tarojs/taro";
 import React from "react";
 import { useTranslation } from "react-i18next";
+import { TimeFormatter } from "@/utils/time_format";
 // export default function Component(props: { limit: number, onChange: Function, onCancel: Function,isRealTime?:boolean,limitDay?:number,time?:number,ref?:any }) {
 const Component = forwardRef((props: {
     limit: number, onChange: Function, onCancel: Function,
@@ -58,14 +59,14 @@ const Component = forwardRef((props: {
 
         const month = date.getMonth() + 1;
         const day = date.getDate();
-        const weekday = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'][date.getDay()];
-
-        const formattedDate = `${month}月${day}日 ${weekday}`;
+        // const weekday = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'][date.getDay()];
+        const weekday = TimeFormatter.getDayOfWeek(date.getDay());
+        const formattedDate = global.language=='en'?`${weekday} ${TimeFormatter.getMonth(month)} ${day}`:`${TimeFormatter.getMonth(month)}${day}日 ${weekday}`;
         if (i == 0) {
-            days.push('今天 ');
+            days.push(TimeFormatter.getTodayUnit());
         }
         else if (i == 1) {
-            days.push('昨天 ');
+            days.push(TimeFormatter.getYesterdayUnit());
         }
         else {
             days.push(formattedDate);
@@ -226,7 +227,7 @@ const Component = forwardRef((props: {
             <Text className='modal_title' style={{ color: color }}>{props.title ? props.title : '测试标题 '}</Text>
             <View style={{ backgroundColor: 'transparent', position: 'relative' }}>
                 <PickerView
-                    // itemStyle={{ color: '#fff',margin:0,padding:0 }}
+                    itemStyle={{ color: '#fff',margin:0,padding:0 }}
                     value={values}
                     className="picker"
                     maskClass="picker-mask"
@@ -264,11 +265,11 @@ const Component = forwardRef((props: {
             </View>
             <View className='modal_operate'>
                 <View className='modal_btn' style={{ backgroundColor: color + alpha }} onClick={cancel}>
-                    <Text className='modal_cancel_text' style={{ color: color }}>取消</Text>
+                    <Text className='modal_cancel_text' style={{ color: color,fontWeight:'bold' }}>{t('feature.common.picker_cancel_btn')}</Text>
                 </View>
                 <View className='btn_space' />
                 <View className='modal_btn' style={{ backgroundColor: color }} onClick={confirm}>
-                    <Text className='modal_confirm_text' style={{ color: '#000' }}>确定</Text>
+                    <Text className='modal_confirm_text' style={{ color: '#000',fontWeight:'bold' }}>{t('feature.common.picker_confirm_btn')}</Text>
                 </View>
 
 

+ 0 - 276
src/components/input/LimitPickers_backup.tsx

@@ -1,276 +0,0 @@
-import { PickerView, PickerViewColumn, View, Text } from "@tarojs/components";
-import { forwardRef, useEffect, useImperativeHandle, useState } from "react";
-import './LimitPickers.scss'
-import Taro from "@tarojs/taro";
-import React from "react";
-import { useTranslation } from "react-i18next";
-// export default function Component(props: { limit: number, onChange: Function, onCancel: Function,isRealTime?:boolean,limitDay?:number,time?:number,ref?:any }) {
-const Component = forwardRef((props: {
-    limit: number, onChange: Function, onCancel: Function,
-    isRealTime?: boolean, limitDay?: number, time?: number, themeColor?: string, title?: string
-}, ref) => {
-
-    const days: string[] = [];
-    const today = new Date();
-    var color = props.themeColor ? props.themeColor : '#ff0000'
-    var alpha = alphaToHex(0.4)
-    const [values, setValues] = useState([props.limitDay ? props.limitDay - 1 : 6, today.getHours(), today.getMinutes()])
-    const [isDisableConfirm, setIsDisableConfirm] = useState(false)
-    const [count,setCount] = useState(0)
-    const {t} = useTranslation()
-
-    function alphaToHex(alpha) {
-        var alphaValue = Math.round(alpha * 255); // 将透明度乘以255并四舍五入
-        var hexValue = alphaValue.toString(16); // 将整数转换为十六进制字符串
-        if (hexValue.length === 1) {
-            hexValue = "0" + hexValue; // 如果十六进制字符串只有一位,补零
-        }
-        return hexValue;
-    }
-
-    useEffect(() => {
-        global.picker_time = global.set_time
-        if (props.time) {
-            var date = new Date(props.time)
-            setValues([(props.limitDay ? props.limitDay - 1 : 6) - getDaysDiff(date), date.getHours(), date.getMinutes()])
-        }
-    }, [])
-    // useEffect(() => {
-    //     setValues([6, today.getHours(), today.getMinutes()])
-    // }, [props.limit])
-
-    useEffect(() => {
-        var date = new Date();
-        if (!props.isRealTime) {
-            date = new Date(global.set_time);
-        }
-
-        date.setDate(today.getDate() - ((props.limitDay ? props.limitDay - 1 : 6) - values[0]));
-        date.setHours(values[1])
-        date.setMinutes(values[2])
-        global.picker_time = date.getTime()
-    }, [values])
-
-
-    for (let i = props.limitDay ? props.limitDay - 1 : 6; i >= 0; i--) {
-        const date = new Date();
-        date.setDate(today.getDate() - i);
-
-        const month = date.getMonth() + 1;
-        const day = date.getDate();
-        const weekday = ['周日', '周一', '周二', '周三', '周四', '周五', '周六'][date.getDay()];
-
-        const formattedDate = `${month}月${day}日 ${weekday}`;
-        if (i == 0) {
-            days.push('今天 ');
-        }
-        else if (i == 1) {
-            days.push('昨天 ');
-        }
-        else {
-            days.push(formattedDate);
-        }
-
-    }
-
-    const hours: number[] = [];
-
-
-    for (let i = 0; i <= 23; i++) {
-        hours.push(i);
-    }
-
-    const minutes: number[] = [];
-    for (let i = 0; i <= 59; i++) {
-        minutes.push(i);
-    }
-
-
-
-    function getTimestamp(dateTimeString: string): number {
-        const timestamp = Date.parse(dateTimeString);
-        return timestamp;
-    }
-
-    function getDaysDiff(date: Date): number {
-        const today = new Date();
-        today.setHours(0, 0, 0, 0);
-
-        const targetDate = new Date(date.getFullYear(), date.getMonth(), date.getDate());
-        targetDate.setHours(0, 0, 0, 0);
-
-        const timeDiff = today.getTime() - targetDate.getTime();
-        const daysDiff = Math.floor(timeDiff / (1000 * 60 * 60 * 24));
-
-        return daysDiff;
-    }
-
-    function onPickerChange(e) {
-        // console.log('picker change')
-        // console.log(e.detail.value)
-        var list = e.detail.value
-
-        const date = new Date();
-        date.setDate(today.getDate() - ((props.limitDay ? props.limitDay - 1 : 6) - list[0]));
-        const year = date.getFullYear();
-        const month = date.getMonth() + 1;
-        const day = date.getDate();
-
-        const time = `${year}-${expandZero(month)}-${expandZero(day)}T${expandZero(hours[list[1]])}:${expandZero(minutes[list[2]])}:00`;
-        // if (getTimestamp(time) > today.getTime()) {
-        //     setValues([list[0], today.getHours(), today.getMinutes()])
-        // }
-        if (getTimestamp(time) > global.set_time) {
-            // console.log('oppsu')
-            Taro.showToast({
-                icon: 'none',
-                title: t('feature.common.toast.min_value'),
-            })
-            // console.log(list[0], (new Date(global.set_time)).getHours(), (new Date(global.set_time)).getMinutes())
-            setValues([list[0], (new Date(global.set_time)).getHours(), (new Date(global.set_time)).getMinutes()])
-            disableConfirm()
-        }
-        else {
-            var limitDate = new Date(props.limit)
-
-            if (getTimestamp(time) < props.limit) {
-                Taro.showToast({
-                    icon: 'none',
-                    title: t('feature.common.toast.max_value'),
-                })
-                setValues([(props.limitDay ? props.limitDay - 1 : 6) - getDaysDiff(limitDate), limitDate.getHours(), limitDate.getMinutes()])
-                disableConfirm()
-                return
-            }
-
-            setValues(e.detail.value)
-
-            //把picker变动时间存储起来
-            setPickerTime();
-        }
-
-    }
-
-    function onPickerEnd(e){
-        // console.log(e)
-        // console.log(values)
-        // setValues(values)
-        // setCount(count+1)
-    }
-
-    function disableConfirm() {
-        setIsDisableConfirm(true)
-        setTimeout(() => {
-            setIsDisableConfirm(false)
-        }, 2000);
-    }
-
-    function expandZero(num: number): string {
-        return num < 10 ? `0${num}` : `${num}`;
-    }
-
-    function cancel(e) {
-        if (process.env.TARO_ENV == 'weapp') {
-            e.stopPropagation()
-        }
-        props.onCancel()
-    }
-
-    function confirm(e) {
-        if (process.env.TARO_ENV == 'weapp') {
-            e.stopPropagation()
-        }
-        if (isDisableConfirm) {
-            return;
-        }
-        var date = new Date();
-        if (!props.isRealTime) {
-            date = new Date(global.set_time);
-        }
-
-        date.setDate(today.getDate() - ((props.limitDay ? props.limitDay - 1 : 6) - values[0]));
-        date.setHours(values[1])
-        date.setMinutes(values[2])
-        props.onChange(date.getTime())
-    }
-
-    function setPickerTime() {
-
-    }
-
-    function getConfirmData() {
-        var date = new Date();
-        if (!props.isRealTime) {
-            date = new Date(global.set_time);
-        }
-
-
-        date.setDate(today.getDate() - ((props.limitDay ? props.limitDay - 1 : 6) - values[0]));
-        date.setHours(values[1])
-        date.setMinutes(values[2])
-        return date.getTime()
-    }
-
-    useImperativeHandle(ref, () => ({
-        getConfirmData: getConfirmData
-    }));
-
-    function pickerDetail() {
-        return <View style={{ display: 'flex', flexDirection: 'column' }}>
-            <Text className='modal_title' style={{ color: color }}>{props.title ? props.title : '测试标题 '}</Text>
-            <View style={{ backgroundColor: 'transparent', position: 'relative' }}>
-                <PickerView
-                    value={values}
-                    className="picker"
-                    maskClass="picker-mask"
-                    onChange={onPickerChange}
-                    onPickEnd={onPickerEnd}
-                    immediateChange={true}
-                    indicatorStyle='height: 50px;color:red;'>
-                    <PickerViewColumn style='flex:0 0 45%'>
-                        {days.map(item => {
-                            return (
-                                <View style={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}>{item}</View>
-                            );
-                        })}
-                    </PickerViewColumn>
-                    <PickerViewColumn>
-                        {hours.map(item => {
-                            return (
-                                <View style={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}>{item < 10 ? `0${item}` : item}</View>
-                            );
-                        })}
-                    </PickerViewColumn>
-                    <PickerViewColumn>
-                        {minutes.map(item => {
-                            return (
-                                <View style={{ display: 'flex', alignItems: 'center', justifyContent: 'center' }}>{item < 10 ? `0${item}` : item}</View>
-                            );
-                        })}
-                    </PickerViewColumn>
-                </PickerView>
-
-                {/* <View className="point_bg1 ">
-                <Text style={{ color: '#fff', fontSize: 16, fontWeight: 'bold' }}>:</Text>
-            </View> */}
-            </View>
-            <View className='modal_operate'>
-                <View className='modal_btn' style={{ backgroundColor: color + alpha }} onClick={cancel}>
-                    <Text className='modal_cancel_text' style={{ color: color }}>取消</Text>
-                </View>
-                <View className='btn_space' />
-                <View className='modal_btn' style={{ backgroundColor: color }} onClick={confirm}>
-                    <Text className='modal_confirm_text' style={{ color: '#000' }}>确定</Text>
-                </View>
-
-
-            </View>
-        </View>
-    }
-
-    return pickerDetail()
-
-
-})
-
-export default React.memo(Component);;

+ 1 - 1
src/components/input/PickerViews.tsx

@@ -52,7 +52,7 @@ const Component = forwardRef((props: {
         <Text className='modal_title' style={{ color: color }}>{props.title ? props.title : '测试标题 '}</Text>
         <PickerView value={v}
             // color='#fff'
-            // itemStyle={{color:'#fff'}}
+            itemStyle={{color:'#fff'}}
             style={{color:'#fff'}}
             onChange={onPickerChange}
             indicatorStyle='height: 50px;'

+ 0 - 11
src/components/layout/Modal.weapp.tsx

@@ -83,21 +83,10 @@ export default function Modal(props: {
             }
         </View>
         <View className={isDismiss ? 'modal_bottom_content modal_bottom_dismiss' : 'modal_bottom_content'} style={{ flexShrink: 0 }} onClick={onClick}>
-            {/* <Text className='modal_title' style={{ color: color }}>{props.title ? props.title : '测试标题 '}</Text> */}
             {
                 props.children
             }
-            {/* <View className='modal_operate'>
-                <View className='modal_btn' style={{ backgroundColor: color+alpha }} onClick={() => props.dismiss()}>
-                    <Text className='modal_cancel_text' style={{color:color}}>取消</Text>
-                </View>
-                <View className='btn_space' />
-                <View className='modal_btn' style={{ backgroundColor: color }} onClick={() => props.confirm()}>
-                    <Text className='modal_confirm_text' style={{color:'#000'}}>确定</Text>
-                </View>
-
 
-            </View> */}
         </View>
 
     </View>

+ 350 - 73
src/context/locales/en.js

@@ -1,90 +1,367 @@
 export default {
-    tabbar:{
-        clock:'Circadian Clock',
-        metric:'Metric',
-        activity:'Activity',
-        nutrition:'Nutrition',
-        more:'More'
+    tabbar: {
+        clock: 'Circadian Clock',
+        metric: 'Metric',
+        activity: 'Activity',
+        nutrition: 'Nutrition',
+        more: 'More'
     },
-    page:{
-        clock:{
-            title:'Circadian Clock',
-            schedule:{
-                title:'Schedule',
-            }
+    share: {
+        title: 'Weight Loss/Fasting Sleep/Body Management/Metric Recording/Exercise Check-in, all in fast16cc',
+        food_title: 'Food Journal'
+    },
+    page: {
+        clock: {
+            title: 'Biological Clock',
+        },
+        activity: {
+            title: 'Activity',
+        },
+        metric: {
+            title: 'Metrics',
         },
-        metric:{
-            title:'Metric',
+        food: {
+            title: 'Food',
         },
-        activity:{
-            title:'Activity',
+        more: {
+            title: 'More',
+            un_login: 'Not Logged In',
+            stone: 'Reverse Aging Stone',
+            stone_desc: 'Member system upgrading, during which metric recording is temporarily exempt from reverse aging stone recording. Please stay tuned.',
+            setting: 'Settings',
+            reset_session: 'Reset Session',
+            debug_mode: 'Debug Mode'
         },
-        more:{
-            title:'More'
+        choose_scenario: {
+            title: 'Choose Biological Clock',
+            title_size: 25,
+            sub_title: 'Fasting and sleep constitute the biological clock',
+            btn_next: 'Next',
+            btn_more: 'Learn More',
         },
-        choose_language:{
-            title:'',
-            sub_title:'',
-            btn_confirm:''
+        set_schedule: {
+            fast_title: 'Fasting Schedule',
+            sleep_title: 'Sleep Schedule',
+            fast_subtitle: 'Set time and duration goals',
+            sleep_subtitle: 'Set time and duration goals',
         },
-        choose_auth:{
-            app_name:'',
-            btn_create_account:'',
-            btn_login:'登录',
-            btn_wechat:'微信登录'
+        choose_language: {
+            title: '',
+            sub_title: '',
+            btn_confirm: ''
         },
-        auth:{
-            agreement:'I agree to the Terms of Service and Privacy Policy.'
+        choose_auth: {
+            app_name: '',
+            btn_create_account: '',
+            btn_login: 'Log In',
+            btn_wechat: 'WeChat Log In',
+            btn_signup: 'Sign Up',
+            slogan: 'Healthy Biological Clock'
         },
-        choose_scenario:{
-            title:'Choose scenario',
-            sub_title:'A scenario clock will display on homepage',
-            btn_next:'Next',
-            btn_more:'Learn more',
-            fast:'Fast',
-            sleep:'Sleep',
-            fast_sleep:'Fast Sleep',
+        auth: {
+            agreement: 'I have read and agreed to the User Agreement and Privacy Policy',
         },
-        set_goal:{
-            title:'',
-            btn_done:''
+        records_history: {
+            time_title: 'Fasting and Sleep',
+            metric_title: '{{title}} Records',
+            activity_title: '{{title}} Records',
+            del_success: 'Deletion Successful'
         },
-        
-        
+        setting: {
+            title: 'Settings',
+            version: 'Version',
+            logout: 'Log Out'
+        },
+        user_profile: {
+            title: 'Edit Profile',
+            nickname: 'Nickname',
+            save: 'Save'
+        }
     },
-    feature:{
-        
-        auth:{
-            create_account:{
-                title:'Create Account',
-                sub_title:'Enter username and email',
-                input_username_placeholder:'Username',
-                input_email_placeholder:'Email',
-                footer_desc:'Already have an account? ',
-                footer_login:'Log in',
-                btn_next:'Next'
-            },
-            login:{
-                input_account_placeholder:'Username or email',
-                input_password_placeholder:'Password',
-                footer_desc:'Don\'t have an account? ',
-                footer_sign_up:'Create account'
-            },
-            create_password:{
-                title:'Create password',
-                sub_title:'Enter password and confirm',
-                input_password_placeholder:'Password',
-                input_password_confirm_placeholder:'Confirm Password',
-                btn_next:'Next'
+    feature: {
+        common: {
+            prompt: 'Prompt',
+            action_sheet_cancel: 'Cancel',
+            picker_cancel_btn: 'Cancel',
+            picker_confirm_btn: 'Confirm',
+            wait_for_end: 'Waiting for End',
+            not_started: 'Not Started',
+            not_completed: 'Not Completed',
+            btn_next: 'Next',
+            btn_done: 'Done',
+            btn_set_and_next: 'Set and Next',
+            btn_set_and_done: 'Set and Done',
+            toast: {
+                min_value: 'Cannot go any lower',
+                max_value: 'Cannot go any higher',
+                min_metric_count: 'Select at least {{count}} items',
+                max_metric_count: 'Advanced members can select more than {{count}} items',
+                min_time_value: 'Cannot go any later',
+                max_time_value: 'Cannot go any earlier',
+                update_success: 'Update Successful',
+                input_nickname: 'Please enter a nickname',
+                ongoing: 'Please complete the record first', // Displayed when the "plus" button or an actionsheet item is clicked while there is an ongoing record
+            },
+            action_sheet: {
+                delete: 'Delete'
+            },
+            modal: {
+                delete_item_title: 'Delete',
+                delete_item_content: 'Are you sure you want to delete?',
+                delete_cancel_btn: 'Cancel',
+                delete_confirm_btn: 'Confirm',
+
+                delete_all_title: 'Delete',
+                delete_all_content: 'Are you sure you want to delete all records?',
+                delete_all_cancel_btn: 'Cancel',
+                delete_all_confirm_btn: 'Confirm',
+
+                logout_title: 'Log Out',
+                logout_content: 'Are you sure you want to log out?',
+
+                deluser_title: 'Delete Account',
+                deluser_content: 'Are you sure you want to delete this account?',
+
+                reset_session_title: 'Reset Session',
+                reset_session_content: 'Are you sure you want to reset the session?'
+            },
+            no_data: {
+                title: 'Failed to Load',
+                retry_btn: 'Retry',
+                no_record: 'No Records'
             }
         },
-        track_time_duration:{
-            action_sheet:{
-                change_schedule:'Change schedule',
-                switch_scenario:'Switch scenario',
-                give_up:'Give up',
-                end_fast:'End fast',
-                cancel:'Cancel'
+
+
+        auth: {
+            create_account: {
+                title: 'Sign Up',
+                sub_title: 'Create Username',
+                input_username_placeholder: 'Username',
+                input_email_placeholder: 'Email',
+                footer_desc: 'Already have an account?',
+                footer_login: 'Go to Login',
+                btn_next: 'Next'
+            },
+            login: {
+                input_account_placeholder: 'Username or Email',
+                input_password_placeholder: 'Password',
+                footer_desc: 'Don\'t have an account?',
+                footer_sign_up: 'Sign Up'
+            },
+            create_password: {
+                title: 'Create Password',
+                sub_title: 'Enter and Confirm Password',
+                input_password_placeholder: 'Password',
+                input_password_confirm_placeholder: 'Confirm Password',
+                btn_next: 'Next'
+            }
+        },
+        track_time_duration: {
+            common: {
+                share_title: 'My Fasting Sleep Diary',
+                start_fast: 'Start Fast',
+                end_fast: 'End Fast',
+                start_sleep: 'Start Sleep',
+                end_sleep: 'End Sleep'
+            },
+            change_tz_alert: {
+                title: 'Detected New Time Zone',
+                content: 'Changed to {{tz}} for you.',
+                confirm: 'Got it'
+            },
+            status_indicator: {
+                fast_wait_for_start:'Fast',
+                fast_ongoing:'Fasting',
+                sleep_wait_for_start:'Sleep',
+                sleep_ongoing:'Sleeping',
+                sleep_ongoing1:'Sleep pending start',
+                sleep_ongoing3:'Sleep ended'
+
+            },
+            follow_wx_pub: {
+                // Unfollowed state
+                modal_unfollowed_title: 'Schedule Reminder',
+                modal_unfollowed_content: 'Follow our public account to enable schedule reminders!',
+                modal_unfollowed_cancel_btn: 'Back',
+                modal_unfollowed_confirm_btn: 'Enable',
+
+                h5_unfollowed_title: 'Enable Schedule Reminders',
+
+                // Followed state
+                modal_followed_title: 'Schedule Reminder Enabled',
+                modal_followed_content: 'Do you want to go to the public account to check?',
+                modal_followed_cancel_btn: 'Back',
+                modal_followed_confirm_btn: 'Go to Check',
+
+                h5_followed_title: 'Schedule Reminders',
+
+            },
+            console: {
+                fast_start: 'Start Fast',
+                fast_end: 'End Fast',
+                sleep_start: 'Start Sleep',
+                sleep_end: 'End Sleep',
+                total_duration: 'Total Duration',
+                countup: 'In Progress',
+                countdown_not_due: 'Time Remaining',
+                timeout: 'Time Expired',
+                fast_duration: 'Fasting Target Duration',
+                sleep_duration: 'Sleep Target Duration',
+                real_fast_start_dt: 'Fast Start Time',
+                real_fast_end_dt: 'Fast End Time',
+                real_sleep_start_dt: 'Sleep Start Time',
+                real_sleep_end_dt: 'Sleep End Time',
+            },
+            schedule: {
+                section_title: 'Today',
+                follow_tip: 'Enable Schedule Reminders',
+                timeout_tip: 'Complete the record and restore the schedule.',
+                action_sheet_adjust_schedule: 'Adjust Schedule',
+                duration_goals_by_stage: 'View Fasting Stage Goals',
+                current_stage: 'View Current Fasting Stage',
+                timeline: 'Schedule',
+                stage: 'Stage',
+
+            },
+            record_fast_sleep: {
+                header: {
+                    latest_record: 'Latest Completed',
+                    btn_show_all: 'View More'
+                },
+                item: {
+                    fast: 'Fasting',
+                    sleep: 'Sleep'
+                },
+                timeline: 'Timeline',
+                stage: 'Stage',
+                pop_title: 'Details'
+            },
+
+            action_sheet: {
+                change_schedule: 'Adjust Schedule',
+                switch_scenario: 'Select Circadian Rhythm',
+                cancel: 'Cancel'
+            },
+            dial: {
+                start_time: 'Start Time',
+                end_time: 'End Time',
+                duration: 'Duration',
+
+                // Secondary modal - picker title
+                picker_fast_schedule_start_time: 'Fast schedule start time',
+                picker_fast_schedule_end_time: 'Fast schedule end time',
+                picker_fast_schedule_duration: 'Fast schedule duration',
+                picker_sleep_schedule_start_time: 'Sleep schedule start time',
+                picker_sleep_schedule_end_time: 'Sleep schedule end time',
+                picker_sleep_schedule_duration: 'Sleep schedule duration',
+            },
+            choose_scenario: {
+                list: {
+                    item1: {
+                        name: 'Fasting',
+                        desc: '',
+                        note: ''
+                    },
+                    item2: {
+                        name: 'Sleep',
+                        desc: '',
+                        note: ''
+                    },
+                    item3: {
+                        name: 'Fasting and Sleep',
+                        desc: '',
+                        note: ''
+                    },
+                }
+            },
+            stage: {
+                a: 'Pre-sleep Fasting',
+                b: 'Fasting during Sleep',
+                c: 'Post-wake Fasting',
+                wait_for_start: 'Waiting to Start',
+                not_completed: 'Not Completed',
+                not_started: 'Not Started'
+            },
+        },
+        food: {
+            action_sheet: {
+                alert_text: 'Edit this meal',
+                edit_title: 'Operate on the current photo',
+                tag: 'Tag',
+                start_time: 'Start Time',
+                end_time: 'End Time',
+                edit_pic: 'Edit Picture',
+                share_pic: 'Share Picture',
+            },
+            picker_tag_title: 'Tag',
+            picker_start_title: 'Start Time',
+            picker_end_title: 'End Time',
+            camera: 'Take Food Photo',
+            album: 'Choose from Album',
+            share_title: 'My Food Diary',
+            prompt: 'Prompt',
+            prompt_detail: 'The order of the diary list has changed, click to refresh',
+            sence_desc: 'Take pictures of food, record pre-meal hunger\nRecord post-meal satiety',
+            sence_desc_off: 'Perceive hunger and satiety signals, improve intuitive eating',
+            learn_more: 'Learn More',
+            mindful_switch_on: 'Mindful mode is turned on',
+            pre_meal_enforce_order_alert: 'Please take a food photo first\nor choose a food photo from the album',
+            pre_meal_confirm_title: 'Pre-meal {{score}} points {{desc}}',
+            post_meal_confirm_title: 'Post-meal {{score}} points {{desc}}',
+            slider_tip_pre_meal_title: 'Hunger',
+            slider_tip_post_meal_title: 'Satiety',
+            slider_tip_pre_meal_desc: 'Extremely hungry to not hungry',
+            slider_tip_post_meal_desc: 'Not full to extremely bloated',
+            disable_switch_modal_title: 'Please complete the current record first',
+            disable_switch_modal_btn: 'Got it'
+        },
+        workout: {
+            share_title: 'My Workout Diary',
+            finish_title: '{{name}} Timer Training',
+            finish_current: 'Please finish the current workout first',
+            add_more: 'Add More',
+            choose_workout: 'Choose Exercise',
+            order: 'Adjust Order',
+            choose_workout_desc: 'Choose exercises frequently practiced in fitness training\nor daily activities'
+        },
+        track_something: {
+            btn_record: 'Record',
+            picker_datetime: 'Record Time',
+            activity: {
+                pop_title: 'Details',
+                btn_status: {
+                    idle: 'Clock In',
+                    ing: 'Clocking In...',
+                    retry: 'Still Clocking In...',
+                    success: 'Clock In Successful',
+                    fail: 'Clock In Failed'
+                },
+                open: 'Open',
+                un_open: 'Not Open',
+                un_login: 'Not Logged In',
+                today_un_check: 'To Clock In Today',
+                check_history: 'View History',
+                login_then_check: 'Clock In after Logging In',
+                open_then_check: 'Clock In Steps after Opening',
+                total: 'Total',
+                sync: 'Sync',
+                check: 'Clock In'
+            },
+            metric: {
+                share_title: 'My Metric Records',
+                no_record: 'No Records',
+                un_login: 'Not Logged In',
+                login_can_check: 'Record after Logging In',
+                check_unlock_data: 'Record to Unlock Trends',
+                choose_metric: 'Choose Metric',
+                order: 'Adjust Order'
+
+            },
+            werun_auth: {
+                modal_open_setting_title: 'Reminder',
+                modal_open_setting_content: 'We noticed that you have not granted permission to access WeChat Workout. Would you like to open settings to grant permission?',
+                toast_reject_auth: 'You have rejected authorization and cannot access step count'
             }
         }
     }

+ 1 - 1
src/context/locales/index.ts

@@ -16,7 +16,7 @@ function getLanguageSetting() {
     }
   }
   else {
-    initLocale('zh')
+    initLocale('en')
   }
 }
 

+ 11 - 1
src/context/locales/zh.js

@@ -169,8 +169,18 @@ export default {
                 start_sleep: '开始睡眠',
                 end_sleep: '结束睡眠'
             },
+            change_tz_alert:{
+                title:'检测到新时区',
+                content:'已为您变更到 {{tz}}',
+                confirm:'我知道了'
+            },
             status_indicator: {
-
+                fast_wait_for_start:'断食',
+                fast_ongoing:'断食进行中',
+                sleep_wait_for_start:'睡眠',
+                sleep_ongoing:'睡眠进行中',
+                sleep_ongoing1:'睡眠待开始',
+                sleep_ongoing3:'睡眠已结束'
             },
             follow_wx_pub: {
                 //未关注状态

+ 1 - 1
src/features/food/FoodTimelineItem.tsx

@@ -80,7 +80,7 @@ export default function Component(props: {
     function operateActionSheet() {
         var itemList = [t('feature.food.action_sheet.tag')]
         var date = TimeFormatter.getMonthAndDayByDate(detail.start.date)
-        if (date == '今天' || date == '昨天') {
+        if (date == TimeFormatter.getTodayUnit() || date == TimeFormatter.getYesterdayUnit()) {
             itemList.push(t('feature.food.action_sheet.start_time'))
             itemList.push(t('feature.food.action_sheet.end_time'))
         }

+ 3 - 3
src/features/trackSomething/components/ActivityHistory.tsx

@@ -36,9 +36,9 @@ export default function Component(props: { records: any[] }) {
         const day = 1000 * 60 * 60 * 24;
 
         if (diff < day) {
-            return '今天';
+            return TimeFormatter.getTodayUnit();
         } else if (diff < 2 * day) {
-            return '昨天';
+            return TimeFormatter.getYesterdayUnit();
         } else {
             return date.substring(0, 4) + '-' +
                 date.substring(4, 6) + '-' +
@@ -87,7 +87,7 @@ export default function Component(props: { records: any[] }) {
             <ScrollView style={{ maxHeight: 400 }} scrollY>
                 <View style={{ display: 'flex', alignItems: 'center', position: 'relative', width: '100%', flexDirection: 'column' }}>
 
-                    <Timeline items={timelineItems} type={TimelineType.timeFirst} showLastLine={TimeFormatter.getMonthAndDayByDate(item.date) == '今天'} />
+                    <Timeline items={timelineItems} type={TimelineType.timeFirst} showLastLine={TimeFormatter.getMonthAndDayByDate(item.date) == TimeFormatter.getTodayUnit()} />
 
                 </View>
             </ScrollView>

+ 2 - 2
src/features/trackSomething/components/MetricHistory.tsx

@@ -25,9 +25,9 @@ export default function Component(props: { records: any[] }) {
         const day = 1000 * 60 * 60 * 24;
 
         if (diff < day) {
-            return '今天';
+            return TimeFormatter.getTodayUnit();
         } else if (diff < 2 * day) {
-            return '昨天';
+            return TimeFormatter.getYesterdayUnit();
         } else {
             return date.substring(0, 4) + '-' +
                 date.substring(4, 6) + '-' +

+ 20 - 0
src/features/trackSomething/components/MetricModalAdd.scss

@@ -0,0 +1,20 @@
+.change_time_bg {
+    height: 140px;
+    display: flex;
+    align-items: center;
+    justify-content: center;
+}
+
+.time_bg{
+    height: 60px;
+    border-radius: 30px;
+    padding-left: 30px;
+    padding-right: 30px;
+}
+
+.time{
+    height: 60px;
+    color: #fff;
+    opacity: 0.4;
+    line-height: 60px;
+}

+ 4 - 4
src/features/trackSomething/components/MetricModalAdd.tsx

@@ -51,15 +51,15 @@ export default function Component(props: { item: any, strTime: string, showPicke
                     })
                 }
             </View>
-            <View className="change_time_bg ">
-                <View className="gray1 time_bg" onClick={() => { props.showPicker(metricItem) }}>
+            <View className="change_time_bg" >
+                <View className="gray1 time_bg"onClick={() => { props.showPicker(metricItem) }}>
                     <Text className="time" >{props.strTime}</Text>
                 </View>
 
             </View>
             <View className='modal_operate'>
                 <View className='modal_btn' style={{ backgroundColor: (metricItem as any).theme_color + alphaToHex(0.4) }} onClick={() => props.cancel()}>
-                    <Text className='modal_cancel_text' style={{ color: (metricItem as any).theme_color }}>{
+                    <Text className='modal_cancel_text' style={{ color: (metricItem as any).theme_color,fontWeight:'bold' }}>{
                         t('feature.common.picker_cancel_btn')
                     }</Text>
                 </View>
@@ -69,7 +69,7 @@ export default function Component(props: { item: any, strTime: string, showPicke
                         props.confirm(metricItem)
                     }
                 }}>
-                    <Text className='modal_confirm_text' style={{ color: '#000' }}>{
+                    <Text className='modal_confirm_text' style={{ color: '#000',fontWeight:'bold' }}>{
                         t('feature.common.picker_confirm_btn')
                     }</Text>
                 </View>

+ 1 - 1
src/features/trackSomething/components/MetricModalChoose.tsx

@@ -183,7 +183,7 @@ export default function Component(props: {
         </ScrollView>
         <View className='modal_operate'>
             <View className='modal_btn' style={{ backgroundColor: color + alpha }} onClick={cancel}>
-                <Text className='modal_cancel_text' style={{ color: color }}>取消</Text>
+                <Text className='modal_cancel_text' style={{ color: color }}>{t('feature.common.picker_cancel_btn')}</Text>
             </View>
             <View className='btn_space' />
             <View className='modal_btn' style={{ backgroundColor: color }} onClick={confirm}>

+ 1 - 1
src/features/trackSomething/components/MetricModalChoose_backup.tsx

@@ -116,7 +116,7 @@ export default function Component(props: { themeColor: string, cancel: Function,
         </ScrollView>
         <View className='modal_operate'>
             <View className='modal_btn' style={{ backgroundColor: color + alpha }} onClick={cancel}>
-                <Text className='modal_cancel_text' style={{ color: color }}>取消</Text>
+                <Text className='modal_cancel_text' style={{ color: color }}>{t('feature.common.picker_cancel_btn')}</Text>
             </View>
             <View className='btn_space' />
             <View className='modal_btn' style={{ backgroundColor: color }} onClick={confirm}>

+ 2 - 2
src/features/trackSomething/components/MetricModalOrder.tsx

@@ -48,11 +48,11 @@ export default function Component(props: { themeColor: string, cancel: Function,
         </View>
         <View className='modal_operate'>
             <View className='modal_btn' style={{ backgroundColor: color + alpha }} onClick={cancel}>
-                <Text className='modal_cancel_text' style={{ color: color }}>{global.metricAdd ? '上一步' : '取消'}</Text>
+                <Text className='modal_cancel_text' style={{ color: color }}>{global.metricAdd ? '上一步' : t('feature.common.picker_cancel_btn')}</Text>
             </View>
             <View className='btn_space' />
             <View className='modal_btn' style={{ backgroundColor: color }} onClick={confirm}>
-                <Text className='modal_confirm_text' style={{ color: '#000' }}>{global.metricAdd ? '完成' : '确定'}</Text>
+                <Text className='modal_confirm_text' style={{ color: '#000' }}>{global.metricAdd ? '完成' : t('feature.common.picker_confirm_btn')}</Text>
             </View>
 
 

+ 66 - 14
src/features/trackTimeDuration/components/ChooseScenario.tsx

@@ -20,10 +20,16 @@ import Layout from "@/components/layout/layout";
 import { ColorType } from "@/context/themes/color";
 import TitleView from "./TitleView";
 import { jumpPage } from "../hooks/Common";
+import { rpxToPx } from "@/utils/tools";
+//import LinearGradient from "react-native-linear-gradient";
 
 let useNavigation;
+let GradientText
+let LinearGradient
 if (process.env.TARO_ENV == 'rn') {
-  useNavigation = require("@react-navigation/native").useNavigation
+    GradientText = require('@/components/basic/GradientText').default
+    useNavigation = require("@react-navigation/native").useNavigation
+    LinearGradient = require('react-native-linear-gradient').default
 }
 export default function Component() {
     const isFastFirst = true;
@@ -37,14 +43,14 @@ export default function Component() {
 
     let navigation;
     if (useNavigation) {
-      navigation = useNavigation()
+        navigation = useNavigation()
     }
 
     useDidShow(() => {
         setCount(count + 1)
     })
 
-    useEffect(()=>{
+    useEffect(() => {
         if (selScenario) {
             if (selScenario.name == 'FAST_SLEEP') {
                 dispatch(setStep(isFastFirst ? 'fast' : 'sleep'))
@@ -60,14 +66,14 @@ export default function Component() {
             }
         }
 
-        if (time){
-            if (time.scenario=='FAST_SLEEP'){
+        if (time) {
+            if (time.scenario == 'FAST_SLEEP') {
                 setSelIndex(2)
             }
-            else if (time.scenario=='SLEEP'){
+            else if (time.scenario == 'SLEEP') {
                 setSelIndex(1)
             }
-            else{
+            else {
                 setSelIndex(0)
             }
         }
@@ -81,10 +87,10 @@ export default function Component() {
             Taro.setStorage({ key: 'scenarios', data: JSON.stringify(data.scenarios as any) })
             setScenarios(data.scenarios)
         })
-    },[])
+    }, [])
 
     useReady(() => {
-        
+
     })
 
     function next() {
@@ -105,7 +111,7 @@ export default function Component() {
                     dispatch(setStep(isFastFirst ? 'fast' : 'sleep'))
                 }
         }
-        jumpPage('/pages/clock/SetSchedule','SetSchedule',navigation)
+        jumpPage('/pages/clock/SetSchedule', 'SetSchedule', navigation)
     }
 
     function footerContent() {
@@ -128,7 +134,26 @@ export default function Component() {
                 break;
         }
         return <View>
-            <ChooseScenarioBtn title={t('feature.common.btn_next')} onClick={next} background={background} />
+            {
+                process.env.TARO_ENV == 'rn' && selIndex == 2 ? <View onClick={next}>
+                    <LinearGradient
+                        style={{
+                            width: 300,
+                            height: 50,
+                            borderRadius: 25,
+                            alignItems: 'center',
+                            justifyContent: 'center',
+                        }}
+                        colors={[ColorType.fast, ColorType.sleep]}
+                        start={{ x: 0, y: 0 }}
+                        end={{ x: 1, y: 0 }}
+                    >
+                        <Text style={{fontWeight:'bold',fontSize:20}}>{t('feature.common.btn_next')}</Text>
+                    </LinearGradient>
+                </View> :
+                    <ChooseScenarioBtn title={t('feature.common.btn_next')} onClick={next} background={background} />
+            }
+
             {/* <Buttons title='Next' onClick={next} btnStyle={{ ...style, width: 320 }} /> */}
         </View>
     }
@@ -242,9 +267,16 @@ export default function Component() {
                     </View>
                 </View>
                 <View className="item_txt_bg">
-                    <Text className="item_txt fast_sleep_text" >{t('feature.track_time_duration.choose_scenario.list.item3.name')}</Text>
                     {
-                        scenarios[2].count > 0 && <View className="scenario_count">
+                        process.env.TARO_ENV == 'weapp' && <Text className="item_txt fast_sleep_text" >{t('feature.track_time_duration.choose_scenario.list.item3.name')}</Text>
+                    }
+                    {
+                        process.env.TARO_ENV == 'rn' && <GradientText style={{ fontSize: rpxToPx(48), fontWeight: 'bold' }}>{t('feature.track_time_duration.choose_scenario.list.item3.name')}</GradientText>
+                    }
+
+                    {
+                        scenarios[2].count > 0 && process.env.TARO_ENV == 'weapp' &&
+                        <View className="scenario_count">
                             <View className="badge_view1" style={{
                                 background: 'linear-gradient(to right, ' +
                                     (global.fastColor ? global.fastColor : ColorType.fast) + ', '
@@ -255,6 +287,17 @@ export default function Component() {
 
                         </View>
                     }
+                    {
+                        scenarios[2].count > 0 && process.env.TARO_ENV == 'rn' && <View className="scenario_count">
+                            <LinearGradient className="badge_view1"
+                                colors={[ColorType.fast, ColorType.sleep]}
+                                start={{ x: 0, y: 0 }}
+                                end={{ x: 1, y: 0 }}
+                            >
+                                <Text className="badge1">x{scenarios[2].count}</Text>
+                            </LinearGradient>
+                        </View>
+                    }
                 </View>
             </View>
         )
@@ -280,6 +323,7 @@ export default function Component() {
         <View className="container">
             <TitleView title={t('page.choose_scenario.title')}
                 subTitle={t('page.choose_scenario.sub_title')}
+                // titleSize={t('page.choose_scenario.title_size')}
             />
             {
                 scenarios.length > 0 && <View style={{ position: 'relative', zIndex: 1 }}>
@@ -288,9 +332,17 @@ export default function Component() {
             }
 
             {
-                process.env.TARO_ENV =='rn'  &&  <View style={{height:30}}/>
+                process.env.TARO_ENV == 'rn' && <View style={{ height: 30 }} />
             }
 
+            {/* <LinearGradient
+                colors={[ ColorType.fast,ColorType.sleep]}
+                start={{ x: 0, y: 0 }}
+                end={{ x: 1, y: 0 }}
+            >
+                <Text>hlsdjgfaspgopdfag</Text>
+            </LinearGradient> */}
+
 
             <Footer children={footerContent()} />
         </View>

+ 11 - 6
src/features/trackTimeDuration/components/Clock.tsx

@@ -8,9 +8,11 @@ import './Clock.scss'
 import { ColorType } from "@/context/themes/color";
 import { useSelector } from "react-redux";
 import { jumpPage } from "../hooks/Common";
+import Taro from "@tarojs/taro";
+import { useTranslation } from "react-i18next";
 
 let GradientText
-if (process.env.TARO_ENV=='rn'){
+if (process.env.TARO_ENV == 'rn') {
     GradientText = require('@/components/basic/GradientText').default
 }
 export default function Component(props: { showCoverView: boolean }) {
@@ -18,7 +20,7 @@ export default function Component(props: { showCoverView: boolean }) {
     const time = useSelector((state: any) => state.time);
     const user = useSelector((state: any) => state.user);
     const [showCover, setShowCover] = useState(props.showCoverView)
-
+    const { t } = useTranslation()
     const [smallCtx, setSmallCtx] = useState(null)
     const [bigCtx, setBigCtx] = useState(null)
 
@@ -40,6 +42,9 @@ export default function Component(props: { showCoverView: boolean }) {
         setShowCover(props.showCoverView)
     }, [props.showCoverView])
 
+    
+
+    
 
     //外环
     function bigRing() {
@@ -121,7 +126,7 @@ export default function Component(props: { showCoverView: boolean }) {
         common.lineWidth = 28;
         var bgRing = getBgRing()
         var realRing = time.scenario == 'FAST_SLEEP' ? getReal(time, false, false) : null
-        var currentDot = time.scenario == 'FAST_SLEEP'?getDot(checkData ? time : null, false):null
+        var currentDot = time.scenario == 'FAST_SLEEP' ? getDot(checkData ? time : null, false) : null
         var targetRing = time.scenario == 'FAST_SLEEP' ? getTarget(time, false) : null
         if (targetRing) {
             targetRing.color = global.sleepColor ? global.sleepColor + '66' : ColorType.sleep + '66'//'rgba(0, 255, 255, 0.4)'
@@ -171,12 +176,12 @@ export default function Component(props: { showCoverView: boolean }) {
                         !checkData && <Text className="clock_text" style={{ fontSize: 24, color: ColorType.fast }}>{TimeFormatter.getCurrentHourAndMinute()}</Text>
                     }
                     {
-                        checkData && process.env.TARO_ENV=='weapp' && time.status == 'WAIT_FOR_START' && time.scenario == 'FAST_SLEEP' &&
+                        checkData && process.env.TARO_ENV == 'weapp' && time.status == 'WAIT_FOR_START' && time.scenario == 'FAST_SLEEP' &&
                         <Text className="clock_text fast_sleep_text" style={{ fontSize: 24 }}>{TimeFormatter.getCurrentHourAndMinute()}</Text>
                     }
                     {
-                        checkData && process.env.TARO_ENV=='rn' && time.status == 'WAIT_FOR_START' && time.scenario == 'FAST_SLEEP' &&
-                        <GradientText style={{fontSize:24}}>{TimeFormatter.getCurrentHourAndMinute()}</GradientText>
+                        checkData && process.env.TARO_ENV == 'rn' && time.status == 'WAIT_FOR_START' && time.scenario == 'FAST_SLEEP' &&
+                        <GradientText style={{ fontSize: 24 }}>{TimeFormatter.getCurrentHourAndMinute()}</GradientText>
                         // <Text className="clock_text fast_sleep_text" style={{ fontSize: 24 }}>{TimeFormatter.getCurrentHourAndMinute()}</Text>
                     }
                     {

+ 12 - 9
src/features/trackTimeDuration/components/Console.tsx

@@ -227,12 +227,13 @@ export default function Component(props: { isNextStep?: boolean }) {
 
     function showFoodGuide() {
         dispatch(setFoodTabBadge(true))
-        Taro.showModal({
-            title: '断食已结束',
-            content: '推荐使用『饮食日记』感知模式,记录你的餐前饥饿感',
-            showCancel: false,
-            confirmText: '我知道了'
-        })
+        if (process.env.TARO_ENV == 'weapp')
+            Taro.showModal({
+                title: '断食已结束',
+                content: '推荐使用『饮食日记』感知模式,记录你的餐前饥饿感',
+                showCancel: false,
+                confirmText: '我知道了'
+            })
     }
 
     function pickerConfirm(t: number) {
@@ -361,7 +362,9 @@ export default function Component(props: { isNextStep?: boolean }) {
         if (props.isNextStep) t = sleepDuration / 60000
         var hour = Math.floor(t / 60)
         var minute = Math.floor(t % 60)
-        return `${hour > 0 ? hour + '小时' : ''}${minute > 0 ? minute + '分钟' : ''}`
+        var hourUnit = TimeFormatter.getPickerDurationHoursUnit()
+        var minuteUnit = TimeFormatter.getPickerDurationMinutesUnit()
+        return `${hour > 0 ? hour + hourUnit : ''}${minute > 0 ? minute + minuteUnit : ''}`
     }
 
     function showDurationPicker(e) {
@@ -556,8 +559,8 @@ export default function Component(props: { isNextStep?: boolean }) {
 
     function onGoingText(isFastData) {
         var className = getClassName(isFastData)
-        if (process.env.TARO_ENV=='rn' && className.indexOf('linear')!=-1){
-            return <GradientText style={{ fontSize: rpxToPx(64), fontWeight: 'bold' }} start={isFastData?ColorType.fast:ColorType.sleep} end={ColorType.alert}>{isFastData ?
+        if (process.env.TARO_ENV == 'rn' && className.indexOf('linear') != -1) {
+            return <GradientText style={{ fontSize: rpxToPx(64), fontWeight: 'bold' }} start={isFastData ? ColorType.fast : ColorType.sleep} end={ColorType.alert}>{isFastData ?
                 TimeFormatter.countdown(time.fast.target_end_time) :
                 TimeFormatter.countdown(time.sleep.target_end_time)}</GradientText>
         }

+ 8 - 8
src/features/trackTimeDuration/components/Rings.rn.tsx

@@ -58,14 +58,14 @@ export default function Component(props: {
 
     function drawContent() {
         var time = new Date();
-        if (timeObj.status != 'WAIT_FOR_START' && timeObj && (timeObj.fast || timeObj.sleep)) {
-            var timestamp = time.getTime()
-            //判断逻辑
-            if (timeObj.fast.real_start_time_zone || timeObj.sleep.real_start_time_zone) {
-                timestamp = TimeFormatter.transferTimestamp(timestamp, timeObj.fast.real_start_time_zone ? timeObj.fast.real_start_time_zone : timeObj.sleep.real_start_time_zone)
-                time = new Date(timestamp)
-            }
-        }
+        // if (timeObj.status != 'WAIT_FOR_START' && timeObj && (timeObj.fast || timeObj.sleep)) {
+        //     var timestamp = time.getTime()
+        //     //判断逻辑
+        //     if (timeObj.fast.real_start_time_zone || timeObj.sleep.real_start_time_zone) {
+        //         timestamp = TimeFormatter.transferTimestamp(timestamp, timeObj.fast.real_start_time_zone ? timeObj.fast.real_start_time_zone : timeObj.sleep.real_start_time_zone)
+        //         time = new Date(timestamp)
+        //     }
+        // }
         var seconds = time.getHours() * 3600 + time.getMinutes() * 60 + time.getSeconds();
         var arc = seconds / 86400 * 2 * Math.PI - Math.PI / 2.0;
 

+ 5 - 6
src/features/trackTimeDuration/components/SetSchedule.rn.tsx

@@ -321,7 +321,7 @@ export default function Component() {
                 t('feature.track_time_duration.dial.picker_fast_schedule_duration') :
                 t('feature.track_time_duration.dial.picker_sleep_schedule_duration')}
             themeColor={scenario.step == 'fast' ? global.fastColor ? global.fastColor : ColorType.fast : global.sleepColor ? global.sleepColor : ColorType.sleep}
-            showBtns={true} onCancel={() => { setIsOpen(false);  }} />
+            showBtns={true} onCancel={() => { setIsOpen(false); }} />
     }
 
     function pickerTitle() {
@@ -359,12 +359,11 @@ export default function Component() {
             <View style={{ color: '#fff', marginTop: rpxToPx(64) }}>
                 <Text className="cell_header">{scenario.step == 'fast' ? '断食目标' : '睡眠目标'}</Text>
                 <View className="cell_full" onClick={() => { setIsModalTimePicker(false); setIsOpen(true) }}>
-                    <Text className="cell_title">时长</Text>
-                    <Text className="cell_value" style={{ color: scenario.step == 'fast' ? ColorType.fast : ColorType.sleep }}>{hours > 0 ? hours + '小时' : ''}{minutes > 0 ? minutes + '分钟' : ''}</Text>
+                    <Text className="cell_title">{t('feature.track_time_duration.dial.duration')}</Text>
+                    <Text className="cell_value" style={{ color: scenario.step == 'fast' ? ColorType.fast : ColorType.sleep }}>{hours > 0 ? hours + TimeFormatter.getPickerDurationHoursUnit() : ''}{minutes > 0 ? minutes + TimeFormatter.getPickerDurationMinutesUnit() : ''}</Text>
                     <Image className="cell_arrow" src={require('@/assets/images/arrow3.png')} />
                 </View>
                 <Text className="cell_footer">时长描述</Text>
-                {/* <Text className="cell_footer">计划每日断食16小时45分钟,其余7小时15分钟进食。</Text> */}
 
                 <View style={{ height: rpxToPx(60) }} />
                 <Text className="cell_header">{scenario.step == 'fast' ? '断食日程' : '睡眠日程'}</Text>
@@ -373,7 +372,7 @@ export default function Component() {
                     setChooseStart(true)
                     setIsTimeOpen(true)
                 }}>
-                    <Text className="cell_title">开始时间</Text>
+                    <Text className="cell_title">{t('feature.track_time_duration.dial.start_time')}</Text>
                     <Text className="cell_value" style={{ color: scenario.step == 'fast' ? ColorType.fast : ColorType.sleep }}>{startTime}</Text>
                     <Image className="cell_arrow" src={require('@/assets/images/arrow3.png')} />
                     <View className="cell_line" style={{ height: 1 / PixelRatio.get() }} />
@@ -383,7 +382,7 @@ export default function Component() {
                     setChooseStart(false)
                     setIsTimeOpen(true)
                 }}>
-                    <Text className="cell_title">结束时间</Text>
+                    <Text className="cell_title">{t('feature.track_time_duration.dial.end_time')}</Text>
                     <Text className="cell_value" style={{ color: scenario.step == 'fast' ? ColorType.fast : ColorType.sleep }}>{endTime}</Text>
                     <Image className="cell_arrow" src={require('@/assets/images/arrow3.png')} />
                 </View>

+ 1 - 1
src/features/trackTimeDuration/components/SetSchedule.weapp.tsx

@@ -360,7 +360,7 @@ export default function Component() {
         </View>
         <View className="duration_bg" style={{ opacity: operateType == 1 || operateType == 2 ? 1 : 0.4, backgroundColor: global.isDebug ? 'pink' : 'transparent' }} onClick={() => { setIsModalTimePicker(false);setIsOpen(true) }}>
           <Text className="duration_title schedule_text_key">{t('feature.track_time_duration.dial.duration')}</Text>
-          <Text className="duration_value schedule_text_value"  >{hours > 0 ? hours + '小时' : ''}{minutes > 0 ? minutes + '分钟' : ''}</Text>
+          <Text className="duration_value schedule_text_value"  >{hours > 0 ? hours + TimeFormatter.getPickerDurationHoursUnit() : ''}{minutes > 0 ? minutes + '分钟' : ''}</Text>
         </View>
 
       </View>

+ 10 - 8
src/features/trackTimeDuration/components/StatusIndicator.tsx

@@ -3,18 +3,20 @@ import './StatusIndicator.scss'
 import { useSelector } from "react-redux";
 import { ColorType } from "@/context/themes/color";
 import { useEffect } from "react";
+import { useTranslation } from "react-i18next";
 
 export default function Component() {
     const time = useSelector((state: any) => state.time);
     const user = useSelector((state: any) => state.user);
+    const {t} = useTranslation()
 
     function getFastName() {
-        var strName = '断食'
+        var strName = t('feature.track_time_duration.status_indicator.fast_wait_for_start')//'断食'
         switch (time.scenario) {
             case 'FAST':
                 {
                     if (time.status == 'ONGOING') {
-                        strName = '断食进行中'
+                        strName = t('feature.track_time_duration.status_indicator.fast_ongoing')//'断食进行中'
                     }
                 }
                 break;
@@ -26,7 +28,7 @@ export default function Component() {
                         case 'ONGOING1':
                         case 'ONGOING2':
                         case 'ONGOING3':
-                            strName = '断食进行中'
+                            strName = t('feature.track_time_duration.status_indicator.fast_ongoing')//'断食进行中'
                             break;
                     }
                 }
@@ -43,14 +45,14 @@ export default function Component() {
     }
 
     function getSleepName() {
-        var strName = '睡眠'
+        var strName = t('feature.track_time_duration.status_indicator.sleep_wait_for_start')//'睡眠'
         switch (time.scenario) {
             case 'FAST':
                 break;
             case 'SLEEP':
                 {
                     if (time.status == 'ONGOING') {
-                        strName = '睡眠进行中'
+                        strName = t('feature.track_time_duration.status_indicator.sleep_ongoing')//'睡眠进行中'
                     }
                 }
                 break;
@@ -58,13 +60,13 @@ export default function Component() {
                 {
                     switch (time.status) {
                         case 'ONGOING1':
-                            strName = '睡眠待开始'
+                            strName = t('feature.track_time_duration.status_indicator.sleep_ongoing1')//'睡眠待开始'
                             break;
                         case 'ONGOING2':
-                            strName = '睡眠进行中'
+                            strName = t('feature.track_time_duration.status_indicator.sleep_ongoing')//'睡眠进行中'
                             break;
                         case 'ONGOING3':
-                            strName = '睡眠已结束'
+                            strName = t('feature.track_time_duration.status_indicator.sleep_ongoing3')//'睡眠已结束'
                             break;
                     }
                 }

+ 3 - 2
src/features/trackTimeDuration/components/TitleView.tsx

@@ -20,7 +20,8 @@ export default function Component(props: {
     titleColor?: string,
     secondPage?: boolean,
     showAddBtn?: boolean,
-    onClick?: Function
+    onClick?: Function,
+    titleSize?: any
 }) {
     const time = useSelector((state: any) => state.time);
     const user = useSelector((state: any) => state.user);
@@ -96,7 +97,7 @@ export default function Component(props: {
         <View className='title_bg'>
             <Text className='title' style={{
                 color: props.titleColor ? props.titleColor : '#fff',
-                fontSize: props.secondPage ? 28 : 36
+                fontSize: props.titleSize?props.titleSize:(props.secondPage ? 28 : 36)
             }}>{props.title}</Text>
             {
                 showAddIcon ? <View className='iconAddBg' onClick={more}>

+ 3 - 3
src/features/trackTimeDuration/hooks/Console.tsx

@@ -11,7 +11,7 @@ export const pickerDurations = () => {
         var count = i * 5 + 60;
         var hour = Math.floor(count / 60);
         var minute = count % 60;
-        list.push(`${hour > 0 ? hour + '小时' : ''}${minute > 0 ? minute + '分钟' : ''}`);
+        list.push(`${hour > 0 ? hour + TimeFormatter.getPickerDurationHoursUnit() : ''}${minute > 0 ? minute + '分钟' : ''}`);
     }
     return list;
 }
@@ -30,11 +30,11 @@ export const durationDatas = (common: any) => {
     }
     var minutes: string[] = []
     for (let i = 0; i < 60; i += step) {
-        minutes.push(i + '分钟')
+        minutes.push(i + TimeFormatter.getPickerDurationMinutesUnit())
     }
     var hours: string[] = []
     for (let i = min; i <= max; i++) {
-        hours.push(i + '小时')
+        hours.push(i + TimeFormatter.getPickerDurationHoursUnit())
     }
     return [hours, minutes]
 }

+ 16 - 12
src/features/trackTimeDuration/hooks/RingData.tsx

@@ -104,9 +104,9 @@ export const getTarget = (data: any, isBigRing: boolean) => {
         }
         else {
             var timestamp = data.fast.target_start_time
-            if (data.fast.real_start_time_zone) {
-                timestamp = TimeFormatter.transferTimestamp(timestamp, data.fast.real_start_time_zone)
-            }
+            // if (data.fast.real_start_time_zone) {
+            //     timestamp = TimeFormatter.transferTimestamp(timestamp, data.fast.real_start_time_zone)
+            // }
             targetRingBig.startArc = startArc(timestamp)
             targetRingBig.durationArc = durationArc(data.fast.target_start_time, data.fast.target_end_time)
         }
@@ -114,9 +114,9 @@ export const getTarget = (data: any, isBigRing: boolean) => {
     }
     else {
         var timestamp = data.sleep.target_start_time
-        if (data.sleep.real_start_time_zone) {
-            timestamp = TimeFormatter.transferTimestamp(timestamp, data.sleep.real_start_time_zone)
-        }
+        // if (data.sleep.real_start_time_zone) {
+        //     timestamp = TimeFormatter.transferTimestamp(timestamp, data.sleep.real_start_time_zone)
+        // }
         targetRingSmall.startArc = startArc(timestamp)
         targetRingSmall.durationArc = durationArc(data.sleep.target_start_time, data.sleep.target_end_time)
         return targetRingSmall
@@ -124,6 +124,7 @@ export const getTarget = (data: any, isBigRing: boolean) => {
 }
 
 export const getReal = (data: any, isBigRing: boolean, isRecord: boolean) => {
+    // console.log(data)
     const realRingBig: RealRing = {
         color: global.fastColor ? global.fastColor : ColorType.fast,
         startArc: 0,
@@ -139,8 +140,8 @@ export const getReal = (data: any, isBigRing: boolean, isRecord: boolean) => {
     if (isBigRing) {
         if (data.scenario == 'SLEEP') {
             realRingBig.color = global.sleepColor ? global.sleepColor : ColorType.sleep
-            if (data.sleep.real_start_time_zone) {
-                var timestamp = TimeFormatter.transferTimestamp(data.sleep.real_start_time, data.sleep.real_start_time_zone)
+            if (data.sleep.real_end_time_zone && data.status == 'COMPLETED') {
+                var timestamp = TimeFormatter.transferTimestamp(data.sleep.real_start_time, data.sleep.real_end_time_zone)
                 realRingBig.startArc = startArc(timestamp)
             }
             else {
@@ -150,8 +151,9 @@ export const getReal = (data: any, isBigRing: boolean, isRecord: boolean) => {
             realRingBig.durationArc = durationArc(data.sleep.real_start_time, isRecord ? (data.sleep.real_end_time ? data.sleep.real_end_time : new Date().getTime()) : new Date().getTime())
         }
         else {
-            if (data.fast.real_start_time_zone) {
-                var timestamp = TimeFormatter.transferTimestamp(data.fast.real_start_time, data.fast.real_start_time_zone)
+            if (data.fast.real_end_time_zone && data.status == 'COMPLETED') {
+                var timestamp = TimeFormatter.transferTimestamp(data.fast.real_start_time, data.fast.real_end_time_zone)
+         
                 realRingBig.startArc = startArc(timestamp)
             }
             else {
@@ -163,8 +165,10 @@ export const getReal = (data: any, isBigRing: boolean, isRecord: boolean) => {
         return realRingBig
     }
     else {
-        if (data.sleep.real_start_time_zone) {
-            var timestamp = TimeFormatter.transferTimestamp(data.sleep.real_start_time, data.sleep.real_start_time_zone)
+        if (data.sleep.real_end_time_zone && data.status == 'COMPLETED') {
+            // alert(data.fast.real_end_time_zone)
+            var timestamp = TimeFormatter.transferTimestamp(data.sleep.real_start_time, data.fast.real_end_time_zone?data.fast.real_end_time_zone:data.sleep.real_end_time_zone)
+            // alert(timestamp)
             realRingSmall.startArc = startArc(timestamp)
         }
         else {

+ 1 - 1
src/pages/account/ProfileSetting.tsx

@@ -144,7 +144,7 @@ export default function Page() {
         <View style={{ flex: 1 }} />
 
         <Footer>
-            <ChooseScenarioBtn disable={router.params.newuser == '1' && (user.avatar == header || user.nickname == name)} title='确定' onClick={() => {
+            <ChooseScenarioBtn disable={router.params.newuser == '1' && (user.avatar == header || user.nickname == name)} title={t('feature.common.picker_confirm_btn')} onClick={() => {
                 if (process.env.TARO_ENV == 'weapp') {
                     Taro.navigateBack()
                 }

+ 47 - 6
src/pages/clock/Clock.weapp.tsx

@@ -47,14 +47,16 @@ import Modal from '@/components/layout/Modal'
 // import Rings from '@components/view/Rings';
 
 let useNavigation;
+let AppState;
 if (process.env.TARO_ENV == 'rn') {
+  AppState = require("react-native").AppState
   useNavigation = require("@react-navigation/native").useNavigation
 }
 
 
 export default function IndexPage() {
   const dispatch = useDispatch();
-  const { t } = useTranslation()
+  const { t,i18n } = useTranslation()
   const [checkData, setCheckData] = useState(null)
   const user = useSelector((state: any) => state.user);
   const time = useSelector((state: any) => state.time);
@@ -93,8 +95,7 @@ export default function IndexPage() {
   }
 
   useEffect(() => {
-    
-    console.log('clock page init')
+    AppState.addEventListener('change', handleAppStateChange);
     global.consoleType = 'idle'
     dispatch(staticResources() as any);
     // dispatch(gobalConfigs() as any);
@@ -114,6 +115,17 @@ export default function IndexPage() {
 
   }, [])
 
+  useEffect(() => {
+    
+    const currentLanguage = i18n.language;
+    global.language = currentLanguage
+    console.log('current language',currentLanguage)
+  }, [])
+
+  const handleAppStateChange = (nextAppState) => {
+    checkTimeZone()
+  };
+
   useEffect(() => {
     setConsoleStatus(consoleData.status)
     switch (consoleData.status) {
@@ -145,6 +157,35 @@ export default function IndexPage() {
     }
   }, [user.isLogin])
 
+  function checkTimeZone() {
+    var split = new Date().toString().split(' ');
+    var timeZoneFormatted = split[split.length - 2];
+
+
+    Taro.getStorage({
+      key: 'last_tz',
+      success: function (res) {
+        if (res.data && res.data != timeZoneFormatted) {
+
+          if (global.currentStatus != 'WAIT_FOR_START') {
+            Taro.showModal({
+              title: t('feature.track_time_duration.change_tz_alert.title'),
+              content: t('feature.track_time_duration.change_tz_alert.content', { tz: timeZoneFormatted }),
+              showCancel: false,
+              confirmText: t('feature.track_time_duration.change_tz_alert.confirm'),
+            })
+          }
+        }
+      },
+      complete: function () {
+        Taro.setStorage({ key: 'last_tz', data: timeZoneFormatted })
+      }
+    })
+
+
+
+  }
+
   function checkSession() {
     if (process.env.TARO_ENV === 'weapp') {
       thirdPartRequest(RequestType.RequestTypeCheckSession).then(res => {
@@ -527,9 +568,9 @@ export default function IndexPage() {
                 checkData && (checkData as any).latest_record &&
                 <SectionHeader top={48} bottom={24} title={t('feature.track_time_duration.record_fast_sleep.header.latest_record')}>
                   <Header title='' action={() => {
-                    jumpPage('/pages/common/RecordsHistory?type=time&title=time','RecordsHistory',navigation,{
-                      type:'time',
-                      title:'time'
+                    jumpPage('/pages/common/RecordsHistory?type=time&title=time', 'RecordsHistory', navigation, {
+                      type: 'time',
+                      title: 'time'
                     })
                   }} />
                 </SectionHeader>

+ 2 - 0
src/store/time.tsx

@@ -21,7 +21,9 @@ const timeSlice = createSlice({
     initialState,
     reducers: {
         updateScenario(state, action: PayloadAction<any>) {
+            
             const { fast, sleep, status, scenario,last_real_check_time } = action.payload;
+            global.currentStatus =  status;
             state.fast = fast
             state.sleep = sleep
             state.status = status

+ 117 - 37
src/utils/time_format.ts

@@ -14,7 +14,7 @@ export class TimeFormatter {
   }
 
   //把本地时间戳更改为指定时区的时间戳
-  static transferTimestamp(timestamp:number,timeZone:string){
+  static transferTimestamp(timestamp: number, timeZone: string) {
     var date = new Date(timestamp)
 
     if (timeZone) {
@@ -41,7 +41,7 @@ export class TimeFormatter {
       inputDate.getMonth() === currentDate.getMonth() &&
       inputDate.getFullYear() === currentDate.getFullYear()
     ) {
-      return `今天 ${TimeFormatter.formatTime(inputDate)}`;
+      return `${TimeFormatter.getTodayUnit()} ${TimeFormatter.formatTime(inputDate)}`;
     }
 
     // 判断是否是昨天
@@ -53,7 +53,7 @@ export class TimeFormatter {
       inputDate.getMonth() === yesterday.getMonth() &&
       inputDate.getFullYear() === yesterday.getFullYear()
     ) {
-      return `昨天 ${TimeFormatter.formatTime(inputDate)}`;
+      return `${TimeFormatter.getYesterdayUnit()} ${TimeFormatter.formatTime(inputDate)}`;
     }
 
     // 判断是否是明天
@@ -65,7 +65,7 @@ export class TimeFormatter {
       inputDate.getMonth() === tomorrow.getMonth() &&
       inputDate.getFullYear() === tomorrow.getFullYear()
     ) {
-      return `明天 ${TimeFormatter.formatTime(inputDate)}`;
+      return `${TimeFormatter.getTomorrowUnit()} ${TimeFormatter.formatTime(inputDate)}`;
     }
 
     // 返回 YYYY-MM-DD HH:mm
@@ -84,7 +84,10 @@ export class TimeFormatter {
       inputDate.getMonth() === currentDate.getMonth() &&
       inputDate.getFullYear() === currentDate.getFullYear()
     ) {
-      return `今天 ${TimeFormatter.padZero(inputDate.getHours())}:${TimeFormatter.padZero(inputDate.getMinutes())}`;
+      // if (global.language == 'en') {
+      //   return `${TimeFormatter.padZero(inputDate.getHours())}:${TimeFormatter.padZero(inputDate.getMinutes())} ${TimeFormatter.getTodayUnit()}`
+      // }
+      return `${TimeFormatter.getTodayUnit()} ${TimeFormatter.padZero(inputDate.getHours())}:${TimeFormatter.padZero(inputDate.getMinutes())}`;
     }
 
     // 判断是否是昨天
@@ -96,9 +99,15 @@ export class TimeFormatter {
       inputDate.getMonth() === yesterday.getMonth() &&
       inputDate.getFullYear() === yesterday.getFullYear()
     ) {
-      return `昨天 ${TimeFormatter.padZero(inputDate.getHours())}:${TimeFormatter.padZero(inputDate.getMinutes())}`;
+      // if (global.language == 'en') {
+      //   return `${TimeFormatter.padZero(inputDate.getHours())}:${TimeFormatter.padZero(inputDate.getMinutes())} ${TimeFormatter.getYesterdayUnit()}`;
+      // }
+      return `${TimeFormatter.getYesterdayUnit()} ${TimeFormatter.padZero(inputDate.getHours())}:${TimeFormatter.padZero(inputDate.getMinutes())}`;
     }
 
+    // if (global.language == 'en') {
+    //   return `${TimeFormatter.padZero(inputDate.getHours())}:${TimeFormatter.padZero(inputDate.getMinutes())} ${TimeFormatter.getDateAndWeek(timestamp)}`
+    // }
     return TimeFormatter.getDateAndWeek(timestamp) + ' ' + `${TimeFormatter.padZero(inputDate.getHours())}:${TimeFormatter.padZero(inputDate.getMinutes())}`
 
   }
@@ -133,10 +142,10 @@ export class TimeFormatter {
       inputDate.getFullYear() === currentDate.getFullYear()
     ) {
       if (currentDate.getTime() - timestamp <= TimeFormatter.nowDuration * 1000 && currentDate.getTime() - timestamp >= 0) {
-        return '刚刚'
+        return TimeFormatter.getJustNowUnit()
       }
 
-      return showToday ? '今天' : ``;
+      return showToday ? TimeFormatter.getTodayUnit() : ``;
     }
 
     // 判断是否是昨天
@@ -148,7 +157,7 @@ export class TimeFormatter {
       inputDate.getMonth() === yesterday.getMonth() &&
       inputDate.getFullYear() === yesterday.getFullYear()
     ) {
-      return `昨天`;
+      return TimeFormatter.getYesterdayUnit();
     }
 
     // 判断是否是明天
@@ -160,7 +169,7 @@ export class TimeFormatter {
       inputDate.getMonth() === tomorrow.getMonth() &&
       inputDate.getFullYear() === tomorrow.getFullYear()
     ) {
-      return `明天`;
+      return TimeFormatter.getTomorrowUnit();
     }
 
 
@@ -169,13 +178,20 @@ export class TimeFormatter {
     const oneDayMilliseconds = 24 * 60 * 60 * 1000; // 一天的毫秒数
     var dayDifference = Math.floor((utcDate2 - utcDate1) / oneDayMilliseconds);
     if (dayDifference < 0) {
-      // dayDifference = 0 - dayDifference;
-      // return `${dayDifference}天前`
+      var strMonth = TimeFormatter.getMonth(inputDate.getMonth() + 1)
       var strDt = ''
+      var strYear = ''
       if (currentDate.getFullYear() != inputDate.getFullYear()) {
-        strDt = inputDate.getFullYear() + '年'
+        strYear = inputDate.getFullYear() + ''
+        strDt = strYear + '年'
       }
-      strDt = strDt + (inputDate.getMonth() + 1) + '月'
+      if (global.language == 'en') {
+        if (strYear.length > 0) {
+          return strMonth + ' ' + inputDate.getDate() + ',' + strYear
+        }
+        return strMonth + ' ' + inputDate.getDate()
+      }
+      strDt = strDt + strMonth
       strDt = strDt + (inputDate.getDate()) + '日'
       return strDt
     }
@@ -208,6 +224,9 @@ export class TimeFormatter {
     return num.toString().padStart(2, '0');
   }
   static getYearByDate(num: number): string {
+    if (global.language == 'en') {
+      return (num + '').substring(0, 4)
+    }
     return (num + '').substring(0, 4) + '年'
   }
 
@@ -222,13 +241,16 @@ export class TimeFormatter {
     const day = 1000 * 60 * 60 * 24;
 
     if (diff < day) {
-      return '今天';
+      return TimeFormatter.getTodayUnit();
     } else if (diff < 2 * day) {
-      return '昨天';
+      return TimeFormatter.getYesterdayUnit();
     } else {
       var month = parseInt((num + '').substring(4, 6))
       var date = parseInt((num + '').substring(6, 8))
-      return month + '月' + date + '日'
+      if (global.language == 'en') {
+        return TimeFormatter.getMonth(month) + ' ' + date
+      }
+      return TimeFormatter.getMonth(month) + date + '日'
     }
   }
 
@@ -261,7 +283,7 @@ export class TimeFormatter {
 
 
   //计算时间间隔
-  static calculateTimeDifference(startTimestamp: number, endTimestamp: number,ingoreSeconds?:boolean): string {
+  static calculateTimeDifference(startTimestamp: number, endTimestamp: number, ingoreSeconds?: boolean): string {
     const diff = Math.abs(endTimestamp - startTimestamp);
     // 计算小时、分钟和秒数
     const hours = Math.floor(diff / (1000 * 60 * 60));
@@ -270,17 +292,14 @@ export class TimeFormatter {
 
     // 根据间隔的大小返回不同的格式
     if (diff < 60000) {
-      return `${seconds}`;
+      return `${seconds}${TimeFormatter.getDurationSecondsUnit(seconds)}`;
     } else if (diff < 3600000) {
-      return `${minutes}分钟`;
-      // return `${minutes}分${seconds}秒`;
+      return `${minutes}${TimeFormatter.getDurationMinutesUnit(minutes)}`;
     } else {
-      // if (ingoreSeconds) return `${hours}小时${minutes}分钟`;
-      // return `${hours}小时${minutes}分${seconds}秒`;
       if (minutes == 0) {
-        return `${hours}小时`;
+        return `${hours}${TimeFormatter.getDurationHoursUnit(hours)}`;
       }
-      return `${hours}小时${minutes}分钟`;
+      return `${hours}${TimeFormatter.getDurationHoursUnit(hours)}${minutes}${TimeFormatter.getDurationMinutesUnit(minutes)}`;
     }
   }
   //格式化时间间隔
@@ -297,7 +316,7 @@ export class TimeFormatter {
     } else if (diff < 3600000) {
       return `00:${TimeFormatter.padZero(minutes)}:${TimeFormatter.padZero(seconds)}`;
     } else {
-      if (ingoreSeconds) return `${hours}小时${minutes}分`;
+      if (ingoreSeconds) return `${hours}${TimeFormatter.getDurationHoursUnit(hours)}${minutes}${TimeFormatter.getDurationMinutesUnit(minutes)}`;
       return `${TimeFormatter.padZero(hours)}:${TimeFormatter.padZero(minutes)}:${TimeFormatter.padZero(seconds)}`;
     }
   }
@@ -372,13 +391,13 @@ export class TimeFormatter {
     const seconds = Math.floor(left % 60);
     var str = ''
     if (hours > 0) {
-      str = str + hours + '小时'
+      str = str + hours + TimeFormatter.getDurationHoursUnit(hours)
     }
     if (minutes > 0) {
-      str = str + minutes + '分钟'
+      str = str + minutes + TimeFormatter.getDurationMinutesUnit(minutes)
     }
     if (seconds > 0) {
-      str = str + seconds + '秒'
+      str = str + seconds + TimeFormatter.getDurationSecondsUnit(seconds)
     }
     return str
   }
@@ -391,15 +410,15 @@ export class TimeFormatter {
     var units: any = []
     if (hours > 0) {
       values.push(hours)
-      units.push('小时')
+      units.push(TimeFormatter.getDurationHoursUnit(hours))
     }
     if (minutes > 0) {
       values.push(minutes)
-      units.push('分钟')
+      units.push(TimeFormatter.getDurationMinutesUnit(minutes))
     }
     if (seconds > 0) {
       values.push(seconds)
-      units.push('秒')
+      units.push(TimeFormatter.getDurationSecondsUnit(seconds))
     }
 
     return {
@@ -421,13 +440,14 @@ export class TimeFormatter {
     const day = 1000 * 60 * 60 * 24;
 
     if (diff < day && !ignore) {
-      return '今天';
+      return TimeFormatter.getTodayUnit();
     } else if (diff < 2 * day && !ignore) {
-      return '昨天';
+      return TimeFormatter.getYesterdayUnit();
     } else {
-
-      var weeks = ['日', '一', '二', '三', '四', '五', '六']
-      return `${dt.getMonth() + 1}月${dt.getDate()}日 星期${weeks[dt.getDay()]}`
+      if (global.language == 'en') {
+        return `${TimeFormatter.getDayOfWeek(dt.getDay())} ${TimeFormatter.getMonth(dt.getMonth() + 1)} ${dt.getDate()}`
+      }
+      return `${TimeFormatter.getMonth(dt.getMonth() + 1)}${dt.getDate()}日 ${TimeFormatter.getDayOfWeek(dt.getDay())}`
     }
   }
 
@@ -439,4 +459,64 @@ export class TimeFormatter {
     // debugger
     return `${TimeFormatter.padZero(now.getHours())}:${TimeFormatter.padZero(now.getMinutes())}`;
   }
+
+  //获取时长单位
+  static getPickerDurationHoursUnit = () => {
+    return global.language == 'en' ? ' H ' : '小时'
+  }
+  static getPickerDurationMinutesUnit = () => {
+    return global.language == 'en' ? ' M' : '分钟'
+  }
+
+  static getDurationHoursUnit = (hours) => {
+    return global.language == 'en' ? hours > 1 ? 'Hours ' : ' Hour ' : '小时'
+  }
+
+  static getDurationMinutesUnit = (minutes) => {
+    return global.language == 'en' ? minutes > 1 ? ' Minutes ' : ' Minute ' : '分钟'
+  }
+
+  static getDurationSecondsUnit = (seconds) => {
+    return global.language == 'en' ? seconds > 1 ? ' Seconds ' : ' Second ' : '秒'
+  }
+
+  static getTodayUnit = () => {
+    return global.language == 'en' ? 'Today' : '今天'
+  }
+
+  static getYesterdayUnit = () => {
+    return global.language == 'en' ? 'Yesterday' : '昨天'
+  }
+
+  static getTomorrowUnit = () => {
+    return global.language == 'en' ? 'Tomorrow' : '明天'
+  }
+
+  static getJustNowUnit = () => {
+    return global.language == 'en' ? 'Just now' : '刚刚'
+  }
+
+  static getDayOfWeek = (index) => {
+    var weeks = ['日', '一', '二', '三', '四', '五', '六']
+    var weeks2 = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'
+    ];
+
+    if (global.language == 'en') {
+      return weeks2[index]
+    }
+    return '星期' + weeks[index]
+
+  }
+
+  static getMonth = (index) => {
+    const monthNames = [
+      'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
+      'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'
+    ];
+    if (global.language == 'en') {
+      return monthNames[index - 1]
+    }
+    return index + '月'
+  }
+
 }

Some files were not shown because too many files changed in this diff