使用 Moment 和 React-i18next 进行日期时间国际化

目录

  1. 前言
  2. 安装依赖
  3. 初始化 i18next
  4. 自定义 Moment 语言包
  5. 在组件中使用 Moment 和 React-i18next
  6. 完整示例
  7. 结论

前言

在开发国际化应用时,不仅需要对文本进行翻译,还需要对日期和时间格式进行国际化处理。本文将展示如何结合 momentreact-i18next 在 React 项目中进行日期和时间的国际化。

安装依赖

首先,我们需要安装必要的依赖包。

npm install moment react-i18next i18next

初始化 i18next

创建一个 i18n.js 文件,并初始化 i18next。同时,我们需要动态设置 moment 的语言。

// src/i18n.js
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import moment from 'moment';
import 'moment/locale/zh-cn'; // 中文
import 'moment/locale/en-gb'; // 英文
 
const resources = {
  en: {
    translation: {
      key: "hello world"
      // 其他翻译...
    }
  },
  zh: {
    translation: {
      key: "你好,世界"
      // 其他翻译...
    }
  }
};
 
i18n
  .use(initReactI18next)
  .init({
    resources,
    lng: 'en', // 默认语言
    fallbackLng: 'en',
    interpolation: {
      escapeValue: false
    }
  });
 
// 动态设置 moment 语言
i18n.on('languageChanged', (lng) => {
  moment.locale(lng);
});
 
export default i18n;

自定义 Moment 语言包

根据需求,可以自定义 moment 的语言包。例如,定义中文语言包:

// src/i18n.js
 
// 自定义中文语言包
moment.updateLocale('zh-cn', {
    months: '一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月'.split('_'),
    monthsShort: '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'),
    weekdays: '星期日_星期一_星期二_星期三_星期四_星期五_星期六'.split('_'),
    weekdaysShort: '周日_周一_周二_周三_周四_周五_周六'.split('_'),
    weekdaysMin: '日_一_二_三_四_五_六'.split('_'),
    longDateFormat: {
        LT: 'HH:mm',
        LTS: 'HH:mm:ss',
        L: 'YYYY-MM-DD',
        LL: 'YYYY年MM月DD日',
        LLL: 'YYYY年MM月DD日Ah点mm分',
        LLLL: 'YYYY年MM月DD日ddddAh点mm分',
        l: 'YYYY-M-D',
        ll: 'YYYY年M月D日',
        lll: 'YYYY年M月D日 HH:mm',
        llll: 'YYYY年M月D日dddd HH:mm'
    },
    meridiemParse: /凌晨|早上|上午|中午|下午|晚上/,
    meridiemHour: function (hour, meridiem) {
        if (hour === 12) {
            hour = 0;
        }
        if (meridiem === '凌晨' || meridiem === '早上' ||
            meridiem === '上午') {
            return hour;
        } else if (meridiem === '下午' || meridiem === '晚上') {
            return hour + 12;
        } else {
            // '中午'
            return hour >= 11 ? hour : hour + 12;
        }
    },
    meridiem: function (hour, minute, isLower) {
        const hm = hour * 100 + minute;
        if (hm < 600) {
            return '凌晨';
        } else if (hm < 900) {
            return '早上';
        } else if (hm < 1130) {
            return '上午';
        } else if (hm < 1230) {
            return '中午';
        } else if (hm < 1800) {
            return '下午';
        } else {
            return '晚上';
        }
    },
    calendar: {
        sameDay: '[今天]LT',
        nextDay: '[明天]LT',
        nextWeek: '[下]ddddLT',
        lastDay: '[昨天]LT',
        lastWeek: '[上]ddddLT',
        sameElse: 'L'
    },
    dayOfMonthOrdinalParse: /\d{1,2}(日||周)/,
    ordinal: function (number, period) {
        switch (period) {
            case 'd':
            case 'D':
            case 'DDD':
                return number + '日';
            case 'M':
                return number + '月';
            case 'w':
            case 'W':
                return number + '周';
            default:
                return number;
        }
    },
    relativeTime: {
        future: '%s内',
        past: '%s前',
        s: '几秒',
        ss: '%d秒',
        m: '1分钟',
        mm: '%d分钟',
        h: '1小时',
        hh: '%d小时',
        d: '1天',
        dd: '%d天',
        M: '1个月',
        MM: '%d个月',
        y: '1年',
        yy: '%d年'
    },
    week: {
        dow: 1, // Monday is the first day of the week.
        doy: 4  // The week that contains Jan 4th is the first week of the year.
    }
});

在组件中使用 Moment 和 React-i18next

在组件中使用 momentreact-i18next 来动态管理语言设置。

// src/App.js
import React from 'react';
import { useTranslation } from 'react-i18next';
import moment from 'moment';
import './i18n'; // 确保 i18n.js 被导入
 
const App = () => {
  const { t, i18n } = useTranslation();
 
  const changeLanguage = (lng) => {
    i18n.changeLanguage(lng);
  };
 
  const formattedDate = moment().format('YYYY-MM-DD HH:mm');
 
  return (
    <div>
      <h1>{t('key')}</h1>
      <p>{formattedDate}</p>
      <button onClick={() => changeLanguage('en')}>English</button>
      <button onClick={() => changeLanguage('zh')}>中文</button>
    </div>
  );
};
 
export default App;

完整示例

完整示例代码如下:

文件结构

src/
│
├── i18n.js
├── App.js
├── index.js

i18n.js

import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import moment from 'moment';
import 'moment/locale/zh-cn'; // 中文
import 'moment/locale/en-gb'; // 英文
 
const resources = {
  en: {
    translation: {
      key: "hello world"
      // 其他翻译...
    }
  },
  zh: {
    translation: {
      key: "你好,世界"
      // 其他翻译...
    }
  }
};
 
i18n
  .use(initReactI18next)
  .init({
    resources,
    lng: 'en', // 默认语言
    fallbackLng: 'en',
    interpolation: {
      escapeValue: false
    }
  });
 
// 自定义中文语言包
moment.updateLocale('zh-cn', {
    months: '一月_二月_三月_四月_五月_六月_七月_八月_九月_十月_十一月_十二月'.split('_'),
    monthsShort: '1月_2月_3月_4月_5月_6月_7月_8月_9月_10月_11月_12月'.split('_'),
    weekdays: '星期日_星期一_星期二_星期三_星期四_星期五_星期六'.split('_'),
    weekdaysShort: '周日_周一_周二_周三_周四_周五_周六'.split('_'),
    weekdaysMin: '日_一_二_三_四_五_六'.split('_'),
    longDateFormat: {
        LT: 'HH:mm',
        LTS: 'HH:mm:ss',
        L: 'YYYY-MM
 
-DD',
        LL: 'YYYY年MM月DD日',
        LLL: 'YYYY年MM月DD日Ah点mm分',
        LLLL: 'YYYY年MM月DD日ddddAh点mm分',
        l: 'YYYY-M-D',
        ll: 'YYYY年M月D日',
        lll: 'YYYY年M月D日 HH:mm',
        llll: 'YYYY年M月D日dddd HH:mm'
    },
    meridiemParse: /凌晨|早上|上午|中午|下午|晚上/,
    meridiemHour: function (hour, meridiem) {
        if (hour === 12) {
            hour = 0;
        }
        if (meridiem === '凌晨' || meridiem === '早上' ||
            meridiem === '上午') {
            return hour;
        } else if (meridiem === '下午' || meridiem === '晚上') {
            return hour + 12;
        } else {
            // '中午'
            return hour >= 11 ? hour : hour + 12;
        }
    },
    meridiem: function (hour, minute, isLower) {
        const hm = hour * 100 + minute;
        if (hm < 600) {
            return '凌晨';
        } else if (hm < 900) {
            return '早上';
        } else if (hm < 1130) {
            return '上午';
        } else if (hm < 1230) {
            return '中午';
        } else if (hm < 1800) {
            return '下午';
        } else {
            return '晚上';
        }
    },
    calendar: {
        sameDay: '[今天]LT',
        nextDay: '[明天]LT',
        nextWeek: '[下]ddddLT',
        lastDay: '[昨天]LT',
        lastWeek: '[上]ddddLT',
        sameElse: 'L'
    },
    dayOfMonthOrdinalParse: /\d{1,2}(日||周)/,
    ordinal: function (number, period) {
        switch (period) {
            case 'd':
            case 'D':
            case 'DDD':
                return number + '日';
            case 'M':
                return number + '月';
            case 'w':
            case 'W':
                return number + '周';
            default:
                return number;
        }
    },
    relativeTime: {
        future: '%s内',
        past: '%s前',
        s: '几秒',
        ss: '%d秒',
        m: '1分钟',
        mm: '%d分钟',
        h: '1小时',
        hh: '%d小时',
        d: '1天',
        dd: '%d天',
        M: '1个月',
        MM: '%d个月',
        y: '1年',
        yy: '%d年'
    },
    week: {
        dow: 1, // Monday is the first day of the week.
        doy: 4  // The week that contains Jan 4th is the first week of the year.
    }
});
 
// 动态设置 moment 语言
i18n.on('languageChanged', (lng) => {
  moment.locale(lng);
});
 
export default i18n;

App.js

import React from 'react';
import { useTranslation } from 'react-i18next';
import moment from 'moment';
import './i18n'; // 确保 i18n.js 被导入
 
const App = () => {
  const { t, i18n } = useTranslation();
 
  const changeLanguage = (lng) => {
    i18n.changeLanguage(lng);
  };
 
  const formattedDate = moment().format('YYYY-MM-DD HH:mm');
 
  return (
    <div>
      <h1>{t('key')}</h1>
      <p>{formattedDate}</p>
      <button onClick={() => changeLanguage('en')}>English</button>
      <button onClick={() => changeLanguage('zh')}>中文</button>
    </div>
  );
};
 
export default App;

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
 
ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

结论

通过上述步骤,我们成功地将 momentreact-i18next 结合使用,实现了日期和时间的国际化处理。你可以根据实际项目需求进一步扩展和自定义语言包。