🕐

DateTimeをintlなしで日本語表示にできるのか?

2024/09/23に公開

そもそもintlとは?

official

Provides internationalization and localization facilities, including message translation, plurals and genders, date/number formatting and parsing, and bidirectional text.

メッセージ翻訳、複数形と性別、日付/数値の書式設定と解析、双方向テキストなどの国際化およびローカリゼーション機能を提供します。

よく使うとしたら、Cloud FirestoreからTimestampを取得したときに日本時間に加工するときが多い気がします。

これぐらい自作できないものかと考えた😅
パッケージなしでは難しいらしい?
でも見た目が、1989年09月28日(月)なら良いのでやってみた。こんな感じの見た目を作ってみる。

DateTimeを拡張して作ったメソッドを使えば実現できるようだ。

extension JapaneseDateTime on DateTime {
  static const List<String> _weekdays = ['月', '火', '水', '木', '金', '土', '日'];
  
  String toJapaneseString() {
    return '$year年${month.toString().padLeft(2, '0')}月${day.toString().padLeft(2, '0')}日(${_weekdays[weekday - 1]})';
  }
  
  String toFormattedString() {
    return '$year ${month.toString().padLeft(2, '0')}:${day.toString().padLeft(2, '0')}';
  }
}

What padLeft?

標準機能として持っているようで内部実装を見てみました。

/// If [width] is already smaller than or equal to `this.length`,
/// no padding is added. A negative `width` is treated as zero.
///
/// If [padding] has length different from 1, the result will not
/// have length `width`. This may be useful for cases where the
/// padding is a longer string representing a single character, like
/// `"&nbsp;"` or `"\u{10002}`".
/// In that case, the user should make sure that `this.length` is
/// the correct measure of the string's length.
String padLeft(int width, [String padding = ' ']);

翻訳すると文字列の長さを測定するメソッドなのかな?

/// [width]がすでに`this.length`より小さいか等しい場合、
/// パディングは追加されない。負の `width` はゼロとして扱われる。
///
/// [padding] の長さが 1 以外である場合、結果は /// 長さ `width` を持たない。
/// 長さ `width` を持たない。これは
/// のように、パディングが1文字を表す長い文字列である場合に有用である。
/// `「&nbsp;」` や `「 \u{10002}`」 のような長い文字列の場合に便利です。
この場合、ユーザーは `this.length` が /// 文字列の正しい長さであることを確認する必要があります。
/// 文字列の長さを正しく測定する必要があります。
String padLeft(int width, [String padding = ' '])

FlutterのWidget内で使用するときは、DateTime.now()の後に.をつけると呼び出すことができます。

Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        Text(
          DateTime.now().toJapaneseString(),
          style: const TextStyle(fontSize: 24),
        ),
        const SizedBox(height: 20),
        Text(
          DateTime.now().toFormattedString(),
          style: const TextStyle(fontSize: 24),
        ),
        // extensionなしの時間
        const SizedBox(height: 20),
        Text(
          DateTime.now().toString(),
          style: const TextStyle(fontSize: 24),
        ),
      ],
    ),

全体のコード

import 'package:flutter/material.dart';

extension JapaneseDateTime on DateTime {
  static const List<String> _weekdays = ['月', '火', '水', '木', '金', '土', '日'];
  
  String toJapaneseString() {
    return '$year年${month.toString().padLeft(2, '0')}月${day.toString().padLeft(2, '0')}日(${_weekdays[weekday - 1]})';
  }
  
  String toFormattedString() {
    return '$year ${month.toString().padLeft(2, '0')}:${day.toString().padLeft(2, '0')}';
  }
}

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    return const MaterialApp(
      home: HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  const HomePage({
    super.key,
  });

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text('日本語日付表示')),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              DateTime.now().toJapaneseString(),
              style: const TextStyle(fontSize: 24),
            ),
            const SizedBox(height: 20),
            Text(
              DateTime.now().toFormattedString(),
              style: const TextStyle(fontSize: 24),
            ),
            // extensionなしの時間
            const SizedBox(height: 20),
            Text(
              DateTime.now().toString(),
              style: const TextStyle(fontSize: 24),
            ),
          ],
        ),
      ),
    );
  }
}

最後に

時間を扱うロジックは仕事でよく使うことがあるのでちょっとしたネタとして記事にしました。僕より優秀な人は計算の処理が必要なロジック作っていたのであっちの方がすごいのですが、現在時刻しか扱わないロジックは難しいものではなかったりするので、できるだけわかりやすいコードで書きたいと思いましたね。
彼たちが書くと無駄にコードが多くて読みづらくて💦

Tips

localizationって言葉が出てくること多いですがこれは時間だけを扱うものではありません。多言語対応もこれに含まれる。

localizationとは、ソフトウェアやアプリケーションを異なる言語や地域の要件に適応させるプロセスです。これには、テキストの翻訳だけでなく、日付、時間、通貨の形式、数値の表記方法など、文化的な違いに応じた調整も含まれます。

localizationの主な目的は以下のとおりです:

  1. 言語の翻訳: ユーザーインターフェース、メッセージ、ヘルプテキストなどを様々な言語に翻訳します。

  2. 地域設定の適応: 日付、時間、通貨の表示形式を各地域の慣習に合わせます。

  3. 文化的な配慮: 色、アイコン、画像などを文化的に適切なものに調整します。

  4. 法的要件の遵守: 各国の法律や規制に準拠したコンテンツや機能を提供します。

  5. ユーザー体験の向上: ローカライズされたアプリケーションは、ユーザーにとってより親しみやすく、使いやすいものとなります。

Flutterでのlocalizationに関しては、公式ドキュメントが非常に参考になります。以下のリンクを参照してください:

  1. Flutter公式ドキュメント - Internationalization:

  2. Flutter公式ドキュメント - Localizing Flutter apps:

https://flutter.dev/docs/development/accessibility-and-localization/internationalization

これらのリソースは、Flutterアプリケーションのlocalizationについて詳細な情報と実装方法を提供しています。特に、Flutter公式ドキュメントでは、flutter_localizationsパッケージの使用方法や、intlパッケージを使用した翻訳の管理方法について説明されています。

また、localizationの実装には、以下のようなサードパーティのパッケージも利用できます:

easy_localization パッケージ:
https://pub.dev/packages/easy_localization

これらのパッケージは、localizationのプロセスを簡略化し、より効率的に多言語対応のアプリケーションを開発するのに役立ちます。

localizationは、グローバル市場でのアプリケーションの成功に不可欠な要素です。ユーザーに母国語でのエクスペリエンスを提供することで、アプリケーションの使いやすさと受け入れやすさが大幅に向上します。

Discussion