Expo で Locale + Language (言語情報)を取得して、DateTimePicker をローカライズして表示する

React Native の DateTimePicker のカレンダーをローカライズされた形で表示させたいケースがあると思います。

iOS に限り、 locale というプロパティでローカライズできるようです。

https://github.com/react-native-datetimepicker/datetimepicker

地域や言語の情報は expo-localization を使って取得します。

expo-localization をインストールします。

shell
npx expo install expo-localization

Expo の Localization については以下のドキュメントに詳細があります。

https://docs.expo.dev/versions/latest/sdk/localization/

取得部分のコードは以下のとおりです。

Sample.ts
import { getLocales } from 'expo-localization';
const locales = getLocales();
const languageTag = locales[0].languageTag;
console.log('locales:', locales[0].languageTag);

日本語環境の場合、locales: ja-JP のように表示されます。

設定 > 一般 > 言語と地域 > 地域 を「アメリカ合衆国」に変更したら、 ja-US になります。 - で区切られた後ろ側が「地域」になるわけですね。前半は「言語」なので、設定で言語を「英語」にすると、 en-US になります。

en-US の場合、カレンダーは June 2023 のようにアメリカっぽく表示されます。

日付は Jun 26, 2023 で表示されてますね。

DateTimePicker のコードは以下のようにしています。

DateTimePicker.tsx
        <DateTimePicker
          testID="dateTimePickerStart"
          value={registerDate}
          mode="date"
          display="default"
          onChange={onRegisterDateChange}
          locale={languageTag}
        />

ダイアログ全体のコードは以下のようになっています。自分の作っているアプリの特性が前面に出ていますが、その辺は無視して、参考にできる部分をつまみ食いしていただければと思います。

Component.tsx
import { convertUTCToLocalISOString } from '../../lib/utils/timeUtil';
import DateTimePicker, { type DateTimePickerEvent } from '@react-native-community/datetimepicker';
import { getLocales } from 'expo-localization';
import React, { useState } from 'react';
import { StyleSheet, View } from 'react-native';
import Dialog from 'react-native-dialog';

interface DocumentingDialogProps {
  documentingDialogVisible: boolean;
  setDocumentingDialogVisible: React.Dispatch<React.SetStateAction<boolean>>;
}

export default function DocumentingDialog({
  documentingDialogVisible,
  setDocumentingDialogVisible,
}: DocumentingDialogProps) {
  const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
  const locales = getLocales();
  const languageTag = locales[0].languageTag;
  const [registerDate, setRegisterDate] = useState<Date>(new Date());
  const onRegisterDateChange = (event: DateTimePickerEvent, selectedDate?: Date) => {
    const currentDate = selectedDate !== undefined ? selectedDate : registerDate;
    setRegisterDate(currentDate);
    console.log('locales:', locales[0].languageTag);
  };
  return (
    <Dialog.Container visible={documentingDialogVisible}>
      <Dialog.Title>努力を記録する</Dialog.Title>
      <Dialog.Description>
        登録する日:{convertUTCToLocalISOString(registerDate.toISOString(), timezone)}
      </Dialog.Description>
      <View style={styles.datePickerWrapper}>
        <DateTimePicker
          testID="dateTimePickerStart"
          value={registerDate}
          mode="date"
          display="default"
          onChange={onRegisterDateChange}
          locale={languageTag}
        />
      </View>

      <Dialog.Button
        label="Cancel"
        onPress={() => {
          setDocumentingDialogVisible(false);
        }}
      />
      <Dialog.Button
        label="OK"
        onPress={async () => {
          // await documentResults(tasks);
          setDocumentingDialogVisible(false);
        }}
      />
    </Dialog.Container>
  );
}

const styles = StyleSheet.create({
  datePickerWrapper: {
    justifyContent: 'center',
    alignItems: 'center',
    marginVertical: 30,
  },
});

この記事を書いているときに作っていたアプリ