ソースコード source code

下記アプリの主要なソースコードを公開しています。アプリ開発の参考になれば幸いです。

画像等が別途必要ですので下記情報のみでアプリが完成するものではありません。 アプリは少しずつ機能拡張していますのでストア公開されているアプリと内容が異なる場合があります。 コードはコピーして自由にお使いいただけます。ただし著作権は放棄しておりませんので全部の再掲載はご遠慮ください。部分的に再掲載したり、改変して再掲載するのは構いません。 自身のアプリ作成の参考として個人使用・商用問わず自由にお使いいただけます。 コード記述のお手本を示すものではありません。ミニアプリですので変数名などさほど気遣いしていない部分も有りますし間違いも有るかと思いますので参考程度にお考え下さい。 他の賢者の皆様が公開されているコードを参考にした箇所も含まれます。Flutter開発の熟練者が書いたコードではありません。 エンジニア向け技術情報共有サービスではありませんので説明は省いています。 GitHubなどへの公開は予定しておりません。

下記コードの最終ビルド日: 2023-11-19

pubspec.yaml

name: compass
description: "Compass"
# The following line prevents the package from being accidentally published to
# pub.dev using `flutter pub publish`. This is preferred for private packages.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev

# The following defines the version and build number for your application.
# A version number is three numbers separated by dots, like 1.2.43
# followed by an optional build number separated by a +.
# Both the version and the builder number may be overridden in flutter
# build by specifying --build-name and --build-number, respectively.
# In Android, build-name is used as versionName while build-number used as versionCode.
# Read more about Android versioning at https://developer.android.com/studio/publish/versioning
# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion.
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
version: 1.0.0+1

environment:
  sdk: '>=3.3.0-143.0.dev <4.0.0'

# Dependencies specify other packages that your package needs in order to work.
# To automatically upgrade your package dependencies to the latest versions
# consider running `flutter pub upgrade --major-versions`. Alternatively,
# dependencies can be manually updated by changing the version numbers below to
# the latest version available on pub.dev. To see which dependencies have newer
# versions available, run `flutter pub outdated`.
dependencies:
  flutter:
    sdk: flutter

  # The following adds the Cupertino Icons font to your application.
  # Use with the CupertinoIcons class for iOS style icons.
  cupertino_icons: ^1.0.6
  package_info_plus: ^4.1.0
  shared_preferences: ^2.0.17
  flutter_localizations:    #多言語ライブラリの本体    # .arbファイルを更新したら flutter gen-l10n
    sdk: flutter
  intl: ^0.18.1     #多言語やフォーマッタなどの関連ライブラリ
  google_mobile_ads: ^3.1.0
  just_audio: ^0.9.35
  flutter_svg: ^2.0.9
  flutter_compass: ^0.8.0
  provider: ^6.1.1

dev_dependencies:
  flutter_test:
    sdk: flutter

  flutter_launcher_icons: ^0.13.1    #flutter pub run flutter_launcher_icons
  flutter_native_splash: ^2.3.5     #flutter pub run flutter_native_splash:create

  # The "flutter_lints" package below contains a set of recommended lints to
  # encourage good coding practices. The lint set provided by the package is
  # activated in the `analysis_options.yaml` file located at the root of your
  # package. See that file for information about deactivating specific lint
  # rules and activating additional ones.
  flutter_lints: ^3.0.1

# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec

flutter_launcher_icons:
  android: "launcher_icon"
  ios: true
  image_path: "assets/icon/icon.png"
  adaptive_icon_background: "assets/icon/icon_back.png"
  adaptive_icon_foreground: "assets/icon/icon_fore.png"

flutter_native_splash:
  color: '#fd12c5'
  image: 'assets/image/splash.png'
  color_dark: '#fd12c5'
  image_dark: 'assets/image/splash.png'
  fullscreen: true
  android_12:
    icon_background_color: '#fd12c5'
    image: 'assets/image/splash.png'
    icon_background_color_dark: '#fd12c5'
    image_dark: 'assets/image/splash.png'

# The following section is specific to Flutter packages.
flutter:
  generate: true    #自動生成フラグの有効化

  # The following line ensures that the Material Icons font is
  # included with your application, so that you can use the icons in
  # the material Icons class.
  uses-material-design: true

  # To add assets to your application, add an assets section, like this:
  # assets:
  #   - images/a_dot_burr.jpeg
  #   - images/a_dot_ham.jpeg
  assets:
    - assets/image/
    - assets/sound/

  # An image asset can refer to one or more resolution-specific "variants", see
  # https://flutter.dev/assets-and-images/#resolution-aware

  # For details regarding adding assets from package dependencies, see
  # https://flutter.dev/assets-and-images/#from-packages

  # To add custom fonts to your application, add a fonts section here,
  # in this "flutter" section. Each entry in this list should have a
  # "family" key with the font family name, and a "fonts" key with a
  # list giving the asset and other descriptors for the font. For
  # example:
  # fonts:
  #   - family: Schyler
  #     fonts:
  #       - asset: fonts/Schyler-Regular.ttf
  #       - asset: fonts/Schyler-Italic.ttf
  #         style: italic
  #   - family: Trajan Pro
  #     fonts:
  #       - asset: fonts/TrajanPro.ttf
  #       - asset: fonts/TrajanPro_Bold.ttf
  #         weight: 700
  #
  # For details regarding fonts from package dependencies,
  # see https://flutter.dev/custom-fonts/#from-packages

lib/ad_mob.dart

///
/// @author akira ohmachi
/// @copyright ao-system, Inc.
/// @date 2023-02-06
///
library;

import 'package:flutter/material.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart';
import 'package:flutter/foundation.dart' show kIsWeb;
import 'dart:io';

class AdMob {
  late BannerAd _adMobBanner;
  bool _isAdMob = false;
  AdMob() { //constructor
    String adBannerUnitId = '';
    if (!kIsWeb && Platform.isAndroid) {
      //adBannerUnitId = 'ca-app-pub-3940256099942544/6300978111';  //test
      adBannerUnitId = 'ca-app-pub-0000000000000000/0000000000';
      _isAdMob = true;
    } else if (!kIsWeb && Platform.isIOS) {
      //adBannerUnitId = 'ca-app-pub-3940256099942544/6300978111';  //test
      adBannerUnitId = 'ca-app-pub-0000000000000000/0000000000';
      _isAdMob = true;
    }
    if (_isAdMob) {
      _adMobBanner = BannerAd(
        adUnitId: adBannerUnitId,
        size: AdSize.banner,
        request: const AdRequest(),
        listener: const BannerAdListener(),
      );
    }
  }
  void load() {
    if (_isAdMob) {
      _adMobBanner.load();
    }
  }
  void dispose() {
    if (_isAdMob) {
      _adMobBanner.dispose();
    }
  }
  Widget getAdBannerWidget() {
    if (_isAdMob) {
      return Container(
        alignment: Alignment.center,
        width: _adMobBanner.size.width.toDouble(),
        height: _adMobBanner.size.height.toDouble(),
        child: AdWidget(ad: _adMobBanner),
      );
    } else {
      return Container();
    }
  }
  double getAdBannerHeight() {
    if (_isAdMob) {
      return _adMobBanner.size.height.toDouble();
    } else {
      return 150;  //for web
    }
  }
}

lib/audio_play.dart

///
/// @author akira ohmachi
/// @copyright ao-system, Inc.
/// @date 2023-01-27
///
library;

import 'package:just_audio/just_audio.dart';

import 'package:compass/const_value.dart';

class AudioPlay {
  //音を重ねて連続再生できるようにインスタンスを用意しておき、順繰りに使う。
  static final List<AudioPlayer> _player01 = [
    AudioPlayer(),
    AudioPlayer(),
    AudioPlayer(),
    AudioPlayer(),
    AudioPlayer(),
    AudioPlayer(),  //6個
  ];
  int _player01Ptr = 0;

  double _soundVolume = 0.0;

  //constructor
  AudioPlay() {
    constructor();
  }
  void constructor() async {
    for (int i = 0; i < _player01.length; i++) {
      await _player01[i].setVolume(0);
      await _player01[i].setAsset(ConstValue.audioHiyoko[i]);
    }
    playZero();
  }
  void dispose() {
    for (int i = 0; i < _player01.length; i++) {
      _player01[i].dispose();
    }
  }
  //getter
  double get soundVolume {
    return _soundVolume;
  }
  //setter
  set soundVolume(double vol) {
    _soundVolume = vol;
  }
  //最初に音が鳴らないのを回避する方法
  void playZero() async {
    AudioPlayer ap = AudioPlayer();
    await ap.setAsset(ConstValue.audioZero);
    await ap.load();
    await ap.play();
  }
  //
  void play01() async {
    if (_soundVolume == 0) {
      return;
    }
    _player01Ptr += 1;
    if (_player01Ptr >= _player01.length) {
      _player01Ptr = 0;
    }
    await _player01[_player01Ptr].setVolume(_soundVolume);
    await _player01[_player01Ptr].pause();
    await _player01[_player01Ptr].seek(Duration.zero);
    await _player01[_player01Ptr].play();
  }
}

lib/compass.dart

///
/// @author akira ohmachi
/// @copyright ao-system, Inc.
/// @date 2023-11-18
///
library;

import 'package:flutter/cupertino.dart';
import 'package:flutter_compass/flutter_compass.dart';

class Compass with ChangeNotifier {
  double _angle = 0;
  get angle {
    return _angle;
  }
  Compass() {
    FlutterCompass.events!.listen((value) {
      _angle = -1 * 3.141592 * (value.heading! / 180);
      notifyListeners();
    });
  }
}

lib/const_value.dart

///
/// @author akira ohmachi
/// @copyright ao-system, Inc.
/// @date 2023-10-15
///
library;

import 'package:flutter/material.dart';

class ConstValue {
  //pref
  static const String prefLanguageCode = 'languageCode';
  static const String prefShowEhou = 'showEhou';
  static const String prefSelectYear = 'selectYear';
  static const String prefShowBackImage = 'showBackImage';
  static const String prefSoundVolume = 'soundVolume';
  //angle
  //5|11|17|23のどれかになる 360度を24分割した位置
  static const Map<int,int> angleEhou = {
    2020:17, //24分割した位置 西南西
    2021:11, //24分割した位置 南南東
    2022:23, //24分割した位置 北北西
    2023:11, //24分割した位置 南南東
    2024:5, //24分割した位置 東北東

	////////////
	// 非公開 //
	////////////

  };
  //image
  static const String imageCompass = 'assets/image/compass.png';
  static const Map<int,String> imageEhou = {
    2020: 'assets/image/ehou2020.png',
    2021: 'assets/image/ehou2021.png',
    2022: 'assets/image/ehou2022.png',

	////////////
	// 非公開 //
	////////////

  };
  static const List<String> imageBacks = [
    'assets/image/back001.webp',
    'assets/image/back002.webp',
    'assets/image/back003.webp',
    'assets/image/back004.webp',
    'assets/image/back005.webp',

	////////////
	// 非公開 //
	////////////

  ];
  //color
  static const Color colorHeader = Color.fromRGBO(200,0,100,0.5);
  static const Color colorSettingAccent = Color.fromRGBO(200,0,100,0.5);
  static const Color colorBack = Color.fromRGBO(50,50,50,1);
  static const Color colorUiActiveColor = Color.fromRGBO(200,0,100,1);
  static const Color colorUiInactiveColor = Colors.black;
  //sound
  static const String audioZero = 'assets/sound/zero.wav';    //無音1秒
  static const List<String> audioHiyoko = [
    'assets/sound/hiyoko1.wav',
    'assets/sound/hiyoko2.wav',
    'assets/sound/hiyoko3.wav',
    'assets/sound/hiyoko4.wav',
    'assets/sound/hiyoko5.wav',
    'assets/sound/hiyoko6.wav',
  ];
  //string
  static const Map<String,String> languageCode = {
    'en': 'English',
    'bg': 'български език',
    'cs': 'Čeština',
    'da': 'dansk',
    'de': 'Deutsch',
    'el': 'Ελληνικά',
    'es': 'Español',
    'et': 'eesti keel',
    'fi': 'Suomen kieli',
    'fr': 'Français',
    'hu': 'magyar nyelv',
    'it': 'Italiano',
    'ja': '日本語',
    'lt': 'lietuvių kalba',
    'lv': 'Latviešu',
    'nl': 'Nederlands',
    'pl': 'Polski',
    'pt': 'Português',
    'ro': 'limba română',
    'ru': 'русский',
    'sk': 'Slovenčina',
    'sv': 'svenska',
    'th': 'ภาษาไทย',
    'zh': '中文',
  };

}

lib/empty.dart

lib/language_state.dart

///
/// @author akira ohmachi
/// @copyright ao-system, Inc.
/// @date 2023-01-27
///
library;

import 'package:compass/preferences.dart';

class LanguageState {

  static String _languageCode = 'en';

  //言語コードを記録
  static Future<void> setLanguageCode(String str) async {
    _languageCode = str;
    await Preferences.setLanguageCode(_languageCode);
  }
  //言語コードを返す
  static Future<String> getLanguageCode() async {
    _languageCode = await Preferences.getLanguageCode() ?? 'en';
    return _languageCode;
  }

}

lib/main.dart

///
/// @author akira ohmachi
/// @copyright ao-system, Inc.
/// @date 2023-10-02
///
library;

import 'dart:math';

import 'package:flutter/material.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:google_mobile_ads/google_mobile_ads.dart' if (dart.library.html) 'empty.dart';
import 'package:flutter/foundation.dart' show kIsWeb;
import 'package:provider/provider.dart';


//自身で作成したclassを読み込む
import 'package:compass/const_value.dart';
import 'package:compass/language_state.dart';
import 'package:compass/version_state.dart';
import 'package:compass/setting.dart';
import 'package:compass/ad_mob.dart';
import 'package:compass/page_state.dart';
import 'package:compass/preferences.dart';
import 'package:compass/audio_play.dart';
import 'package:compass/compass.dart';

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

class MainApp extends StatefulWidget {    //statefulに変更して言語変更に対応
  const MainApp({super.key});
  @override
  State<MainApp> createState() => _MainAppState();
}

class _MainAppState extends State<MainApp> {
  Locale localeLanguage = const Locale('en');
  @override
  Widget build(BuildContext context) {
    if (kIsWeb == false) {
      MobileAds.instance.initialize();
    }
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      localizationsDelegates: AppLocalizations.localizationsDelegates,   //多言語化
      supportedLocales: AppLocalizations.supportedLocales,  //自動で言語リストを生成
      locale: localeLanguage,
      home: const MainHomePage(),
    );
  }
}

class MainHomePage extends StatefulWidget {
  const MainHomePage({super.key});
  @override
  State<MainHomePage> createState() => _MainHomePageState();
}

class _MainHomePageState extends State<MainHomePage> with SingleTickerProviderStateMixin {
  final AdMob _adMob = AdMob(); //広告表示
  final AudioPlay _audioPlay = AudioPlay(); //効果音
  late AnimationController _animationController;
  late Animation<double> _opacityAnimation;
  double _screenSize = 0; //screenWidthとscreenHeightの小さい方
  static const double _compassRatio = 0.95;
  bool _showEhou = true;
  int _selectYear = 2024;
  bool _showBackImage = true;
  int _backImageNumber = 0;
  int _lastBackImageNumber = 0;

  //アプリのバージョン取得
  void _getVersion() async {
    PackageInfo packageInfo = await PackageInfo.fromPlatform();
    setState(() {
      VersionState.versionSave(packageInfo.version);
    });
  }
  //言語準備
  void _getCurrentLocale() async {
    Locale locale = Locale(await LanguageState.getLanguageCode());
    if (mounted) {  //Widgetが存在する。Widgetが存在しない時の実行によるエラーを回避する為。
      context.findAncestorStateOfType<_MainAppState>()!
        ..localeLanguage = locale
        ..setState(() {});
    }
  }
  //ページ起動開始時に一度だけ呼ばれる
  @override
  void initState() {
    super.initState();
    _getVersion();
    _getCurrentLocale();
    LanguageState.getLanguageCode();
    _adMob.load();
    _audioPlay.playZero();
    //background animation
    _animationController = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 500),
    );
    _opacityAnimation = Tween<double>(begin: 0, end: 1).animate(_animationController);
    _animationController.addListener(() {
      setState(() {});
    });
    _backImageChange();
    //
    (() async {
      await Preferences.initial();
      _showEhou = Preferences.showEhou;
      _selectYear = Preferences.selectYear;
      _showBackImage = Preferences.showBackImage;
      _audioPlay.soundVolume = Preferences.soundVolume;
      setState(() {});
    })();
  }
  //ページ終了時に一度だけ呼ばれる
  @override
  void dispose() {
    PageState.setCurrentPage('');
    _adMob.dispose();
    super.dispose();
  }
  //画面全体
  @override
  Widget build(BuildContext context) {
    final double screenWidth = MediaQuery.of(context).size.width;
    final double screenHeight = MediaQuery.of(context).size.height;
    _screenSize = min(screenWidth,screenHeight);
    return ChangeNotifierProvider<Compass>(
      create: (_) => Compass(),
      child: Consumer<Compass>(
        builder: (context, compass, child) {
          return GestureDetector(
            onTap: () {
              _audioPlay.play01();
              _backImageChange();
            },
            child: Container(
              decoration: const BoxDecoration(
                color: ConstValue.colorBack,
              ),
              child: Container(
                decoration: _decoration2(),
                child: Container(
                  decoration: _decoration1(),
                  child: Scaffold(
                    backgroundColor: Colors.transparent, //ここは透明
                    appBar: AppBar(
                      backgroundColor: ConstValue.colorHeader,
                      //タイトル表示
                      title: const Text('Compass',
                        style: TextStyle(
                          color: Colors.white,
                          fontSize: 15.0,
                        )
                      ),
                      //設定ボタン
                      actions: <Widget>[
                        TextButton(
                          onPressed: () async {
                            bool? ret = await Navigator.of(context).push(
                              MaterialPageRoute<bool>(builder:(context) => const SettingPage()),
                            );
                            //awaitで呼び出しているので、settingから戻ったら以下が実行される。
                            if (ret!) { //設定で適用だった場合
                              _getCurrentLocale();
                              _showEhou = Preferences.showEhou;
                              _selectYear = Preferences.selectYear;
                              _showBackImage = Preferences.showBackImage;
                              _audioPlay.soundVolume = Preferences.soundVolume;
                              setState(() {});
                            }
                          },
                          child: Text(
                            AppLocalizations.of(context)!.setting,
                            style: const TextStyle(
                              color: Colors.white,
                            )
                          )
                        )
                      ]
                    ),
                    body: SafeArea(
                      child: Column(children: [
                        Expanded(
                          child: Stack(children:[
                            compassMain(compass.angle),
                            compassEhou(compass.angle),
                          ]),
                        ),
                        //広告
                        Padding(
                          padding: const EdgeInsets.only(top: 10, left: 0, right: 0, bottom: 0),
                          child: SizedBox(
                            width: double.infinity,
                            child: _adMob.getAdBannerWidget(),
                          )
                        )
                      ])
                    )
                  )
                )
              )
            )
          );
        }
      )
    );
  }
  //背景画像前側
  Decoration _decoration1() {
    if (_showBackImage) {
      return BoxDecoration(
          image: DecorationImage(
            image: AssetImage(ConstValue.imageBacks[_backImageNumber]),
            fit: BoxFit.cover,
            colorFilter: ColorFilter.mode(
              Colors.black.withOpacity(_opacityAnimation.value),
              BlendMode.dstATop,
            ),
          )
      );
    } else {
      return const BoxDecoration();
    }
  }
  //背景画像後ろ側
  Decoration _decoration2() {
    if (_showBackImage) {
      return BoxDecoration(
        image: DecorationImage(
          image: AssetImage(ConstValue.imageBacks[_lastBackImageNumber]),
          fit: BoxFit.cover,
        ),
      );
    } else {
      return const BoxDecoration();
    }
  }
  void _backImageChange() {
    final int subSecond = (DateTime.now()).millisecondsSinceEpoch ~/ 100;
    _backImageNumber = subSecond % ConstValue.imageBacks.length;
    _animationController.forward();
    Future.delayed(const Duration(milliseconds: 600), () {
      _lastBackImageNumber = _backImageNumber;
      _animationController.reverse();
    });
  }
  Widget compassMain(double angle) {
    return Center(
      child: Transform.rotate(
        angle: angle,
        child: Image.asset(ConstValue.imageCompass,
          width: _screenSize * _compassRatio,
          height: _screenSize * _compassRatio,
        ),
      ),
    );
  }
  Widget compassEhou(double angle) {
    if (_showEhou) {
      final double ehouAngle = (360 / 180 / 24 * ConstValue.angleEhou[_selectYear]!) * 3.141592;
      return Center(
        child: Opacity(
          opacity: 0.5,
          child: Transform.rotate(
            angle: angle + ehouAngle,
            child: Image.asset(ConstValue.imageEhou[_selectYear]!,
              width: _screenSize * _compassRatio,
              height: _screenSize * _compassRatio,
            )
          )
        )
      );
    } else {
      return Container();
    }
  }
}

lib/page_state.dart

///
/// @author akira ohmachi
/// @copyright ao-system, Inc.
/// @date 2023-10-05
///
library;

//現在のページを記録。initStateでタイミングが合わない時にbuild内で一度だけ実行させるために使用。
class PageState {

  static String _currentPage = '';

  static void setCurrentPage(String str) {
    _currentPage = str;
  }

  static String getCurrentPage() {
    return _currentPage;
  }

}

lib/preferences.dart

///
/// @author akira ohmachi
/// @copyright ao-system, Inc.
/// @date 2023-10-26
///
library;

import 'package:shared_preferences/shared_preferences.dart';

import 'package:compass/const_value.dart';

//デバイスに情報を保存
class Preferences {

  static bool ready = false;
  //この値は常に最新にしておく
  static String _languageCode = '';
  static bool _showEhou = true;
  static int _selectYear = 2023;
  static bool _showBackImage = true;
  static double _soundVolume = 0.3;

  static String get languageCode {
    return _languageCode;
  }
  static bool get showEhou {
    return _showEhou;
  }
  static int get selectYear {
    return _selectYear;
  }
  static bool get showBackImage {
    return _showBackImage;
  }
  static double get soundVolume {
    return _soundVolume;
  }

  static Future<void> initial() async {
    _languageCode = await getLanguageCode();
    _showEhou = await getShowEhou();
    _selectYear = await getSelectYear();
    _showBackImage = await getShowBackImage();
    _soundVolume = await getSoundVolume();
    ready = true;
  }

  //----------------------------

  //言語コード
  static Future<void> setLanguageCode(String str) async {
    _languageCode = str;
    final SharedPreferences prefs = await SharedPreferences.getInstance();
    await prefs.setString(ConstValue.prefLanguageCode, str);
  }
  static Future<String> getLanguageCode() async {
    final SharedPreferences prefs = await SharedPreferences.getInstance();
    final String str = prefs.getString(ConstValue.prefLanguageCode) ?? 'en';
    return str;
  }

  //----------------------------

  //恵方表示
  static Future<void> setShowEhou(bool flag) async {
    _showEhou = flag;
    final SharedPreferences prefs = await SharedPreferences.getInstance();
    await prefs.setBool(ConstValue.prefShowEhou, flag);
  }
  static Future<bool> getShowEhou() async {
    final SharedPreferences prefs = await SharedPreferences.getInstance();
    final bool flag = prefs.getBool(ConstValue.prefShowEhou) ?? true;
    return flag;
  }

  //----------------------------

  //年
  static Future<void> setSelectYear(int num) async {
    _selectYear = num;
    final SharedPreferences prefs = await SharedPreferences.getInstance();
    await prefs.setInt(ConstValue.prefSelectYear, num);
  }
  static Future<int> getSelectYear() async {
    final SharedPreferences prefs = await SharedPreferences.getInstance();
    final int num = prefs.getInt(ConstValue.prefSelectYear) ?? 2024;
    return num;
  }

  //----------------------------

  //背景画像表示
  static Future<void> setShowBackImage(bool flag) async {
    _showBackImage = flag;
    final SharedPreferences prefs = await SharedPreferences.getInstance();
    await prefs.setBool(ConstValue.prefShowBackImage, flag);
  }
  static Future<bool> getShowBackImage() async {
    final SharedPreferences prefs = await SharedPreferences.getInstance();
    final bool flag = prefs.getBool(ConstValue.prefShowBackImage) ?? true;
    return flag;
  }

  //----------------------------

  //効果音音量
  static Future<void> setSoundVolume(double num) async {
    _soundVolume = num;
    final SharedPreferences prefs = await SharedPreferences.getInstance();
    await prefs.setDouble(ConstValue.prefSoundVolume, num);
  }
  static Future<double> getSoundVolume() async {
    final SharedPreferences prefs = await SharedPreferences.getInstance();
    final double num = prefs.getDouble(ConstValue.prefSoundVolume) ?? 0.3;
    return num;
  }

  //----------------------------

}

lib/setting.dart

///
/// @author akira ohmachi
/// @copyright ao-system, Inc.
/// @date 2023-10-15
///
library;

import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';

import 'package:compass/const_value.dart';
import 'package:compass/preferences.dart';
import 'package:compass/language_state.dart';
import 'package:compass/version_state.dart';
import 'package:compass/ad_mob.dart';
import 'package:compass/page_state.dart';

class SettingPage extends StatefulWidget {
  const SettingPage({super.key});

  @override
  State<SettingPage> createState() => _SettingPageState();
}

class _SettingPageState extends State<SettingPage> {
  final AdMob _adMob = AdMob(); //広告
  //これら変数はUIへの表示や入力の為に一時的に使用される。
  String _languageKey = ''; //言語コード 'en'
  String _languageValue = '';
  bool _showEhou = true;
  int _selectYear = 2024;
  bool _setCurrentYear = false;
  bool _showBackImage = true;
  double _soundVolume = 0.0;

  //ページ起動時に一度だけ実行される
  @override
  void initState() {
    super.initState();
    _adMob.load();
  }
  //ページ終了時に一度だけ実行される
  @override
  void dispose() {
    PageState.setCurrentPage('');
    _adMob.dispose();
    super.dispose();
  }
  //ページ描画
  @override
  Widget build(BuildContext context) {
    //このページが開いたときに一度だけ実行される処理を記述。initStateではタイミングが合わない為。
    if (PageState.getCurrentPage() != 'setting') {
      PageState.setCurrentPage('setting');
      (() async {
        _languageKey = await LanguageState.getLanguageCode();
        _languageValue = ConstValue.languageCode[_languageKey] ?? '';
        await Preferences.initial();
        _showEhou = Preferences.showEhou;
        _selectYear = Preferences.selectYear;
        _showBackImage = Preferences.showBackImage;
        _soundVolume = Preferences.soundVolume;
        setState((){});
      })();
    }
    return Scaffold(
      appBar: AppBar(
        centerTitle: true,
        elevation: 0,
        //設定キャンセルボタン
        leading: IconButton(
          icon: const Icon(Icons.close),
          onPressed: () {
            Navigator.of(context).pop(false); //falseを返す
          },
        ),
        title: Text(AppLocalizations.of(context)!.setting),
        foregroundColor: const Color.fromRGBO(255,255,255,1),
        backgroundColor: ConstValue.colorSettingAccent,
        actions: [
          //設定OKボタン
          IconButton(
            icon: const Icon(Icons.check),
            onPressed: () async {
              await LanguageState.setLanguageCode(_languageKey);
              await Preferences.setShowEhou(_showEhou);
              //
              if (_setCurrentYear) {
                _selectYear = (DateTime.now()).year;
                if (_selectYear < ConstValue.angleEhou.keys.first) {
                  _selectYear = ConstValue.angleEhou.keys.first;
                } else if (_selectYear > ConstValue.angleEhou.keys.last) {
                  _selectYear = ConstValue.angleEhou.keys.last;
                }
              }
              await Preferences.setSelectYear(_selectYear);
              //
              await Preferences.setShowBackImage(_showBackImage);
              await Preferences.setSoundVolume(_soundVolume);
              if (!mounted) {
                return;
              }
              Navigator.of(context).pop(true);  //trueを返す
            },
          ),
        ],
      ),
      body: Column(children:[
        Expanded(
          child: GestureDetector(
            onTap: () => FocusScope.of(context).unfocus(),  //背景タップでキーボードを仕舞う
            child: SingleChildScrollView(
              child: Padding(
                padding: const EdgeInsets.all(20),
                child: Column(children: [
                  Padding(
                    padding: const EdgeInsets.only(top: 16, left: 16, right: 16, bottom: 16),
                    child: Row(children:<Widget>[
                      Expanded(
                        child: Text(AppLocalizations.of(context)!.showEhou,style: const TextStyle(fontSize: 16)),
                      ),
                      Switch(
                        value: _showEhou,
                        onChanged: (bool value) {
                          setState(() {
                            _showEhou = value;
                          });
                        },
                        activeColor: ConstValue.colorUiActiveColor,
                        inactiveThumbColor: ConstValue.colorUiInactiveColor,
                      ),
                    ]),
                  ),
                  Padding(
                      padding: const EdgeInsets.only(top: 18, left: 16, right: 16, bottom: 0),
                      child: Row(children: [
                        Text(AppLocalizations.of(context)!.selectYear,style: const TextStyle(fontSize: 16)),
                        const Spacer(),
                      ])
                  ),
                  Padding(
                      padding: const EdgeInsets.only(top: 0, left: 16, right: 16, bottom: 6),
                      child: Row(children: <Widget>[
                        Text(_selectYear.toString()),
                        Expanded(
                            child: Slider(
                              value: _selectYear.toDouble(),
                              min: ConstValue.angleEhou.keys.first.toDouble(),
                              max: ConstValue.angleEhou.keys.last.toDouble(),
                              divisions: ConstValue.angleEhou.keys.last - ConstValue.angleEhou.keys.first - 1,
                              onChanged: (double value) {
                                setState(() {
                                  _selectYear = value.toInt();
                                });
                              },
                              activeColor: ConstValue.colorUiActiveColor,
                              inactiveColor: ConstValue.colorUiInactiveColor,
                            )
                        )
                      ])
                  ),
                  Padding(
                    padding: const EdgeInsets.only(top: 16, left: 16, right: 16, bottom: 16),
                    child: Row(children:<Widget>[
                      Expanded(
                        child: Text(AppLocalizations.of(context)!.setCurrentYear,style: const TextStyle(fontSize: 16)),
                      ),
                      Switch(
                        value: _setCurrentYear,
                        onChanged: (bool value) {
                          setState(() {
                            _setCurrentYear = value;
                          });
                        },
                        activeColor: ConstValue.colorUiActiveColor,
                        inactiveThumbColor: ConstValue.colorUiInactiveColor,
                      ),
                    ]),
                  ),
                  _border(),
                  Padding(
                    padding: const EdgeInsets.only(top: 16, left: 16, right: 16, bottom: 16),
                    child: Row(children:<Widget>[
                      Expanded(
                        child: Text(AppLocalizations.of(context)!.showBackImage,style: const TextStyle(fontSize: 16)),
                      ),
                      Switch(
                        value: _showBackImage,
                        onChanged: (bool value) {
                          setState(() {
                            _showBackImage = value;
                          });
                        },
                        activeColor: ConstValue.colorUiActiveColor,
                        inactiveThumbColor: ConstValue.colorUiInactiveColor,
                      ),
                    ]),
                  ),
                  _border(),
                  Padding(
                    padding: const EdgeInsets.only(top: 18, left: 16, right: 16, bottom: 0),
                    child: Row(children: [
                      Text(AppLocalizations.of(context)!.soundVolume,style: const TextStyle(fontSize: 16)),
                      const Spacer(),
                    ])
                  ),
                  Padding(
                    padding: const EdgeInsets.only(top: 0, left: 16, right: 16, bottom: 6),
                    child: Row(children: <Widget>[
                      Text(_soundVolume.toString()),
                      Expanded(
                        child: Slider(
                          value: _soundVolume,
                          min: 0.0,
                          max: 1.0,
                          divisions: 10,
                          onChanged: (double value) {
                            setState(() {
                              _soundVolume = value;
                            });
                          },
                          activeColor: ConstValue.colorUiActiveColor,
                          inactiveColor: ConstValue.colorUiInactiveColor,
                        )
                      )
                    ])
                  ),
                  _border(),
                  Padding(
                    padding: const EdgeInsets.only(top: 18, left: 0, right: 0, bottom: 0),
                    child: Row(children:[
                      const SizedBox(width:16),
                      Text(AppLocalizations.of(context)!.language,
                        style: const TextStyle(
                          fontSize: 16,
                        )
                      ),
                      const Spacer(),
                    ])
                  ),
                  Padding(
                    padding: const EdgeInsets.only(top: 12, left: 0, right: 0, bottom: 18),
                    child: Table(
                      children: <TableRow>[
                        TableRow(children: <Widget>[
                          _languageTableCell(0),
                          _languageTableCell(1),
                        ]),
                        TableRow(children: <Widget>[
                          _languageTableCell(2),
                          _languageTableCell(3),
                        ]),
                        TableRow(children: <Widget>[
                          _languageTableCell(4),
                          _languageTableCell(5),
                        ]),
                        TableRow(children: <Widget>[
                          _languageTableCell(6),
                          _languageTableCell(7),
                        ]),
                        TableRow(children: <Widget>[
                          _languageTableCell(8),
                          _languageTableCell(9),
                        ]),
                        TableRow(children: <Widget>[
                          _languageTableCell(10),
                          _languageTableCell(11),
                        ]),
                        TableRow(children: <Widget>[
                          _languageTableCell(12),
                          _languageTableCell(13),
                        ]),
                        TableRow(children: <Widget>[
                          _languageTableCell(14),
                          _languageTableCell(15),
                        ]),
                        TableRow(children: <Widget>[
                          _languageTableCell(16),
                          _languageTableCell(17),
                        ]),
                        TableRow(children: <Widget>[
                          _languageTableCell(18),
                          _languageTableCell(19),
                        ]),
                        TableRow(children: <Widget>[
                          _languageTableCell(20),
                          _languageTableCell(21),
                        ]),
                        TableRow(children: <Widget>[
                          _languageTableCell(22),
                          _languageTableCell(23),
                        ]),
                      ]
                    ),
                  ),
                  _border(),
                  Padding(
                    padding: const EdgeInsets.only(top: 24, left: 0, right: 0, bottom: 24),
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children:[
                        Text(AppLocalizations.of(context)!.usage1),
                        const SizedBox(height:15),
                        Text(AppLocalizations.of(context)!.usage2),
                        const SizedBox(height:15),
                        Text(AppLocalizations.of(context)!.usage3),
                        const SizedBox(height:15),
                        Text(AppLocalizations.of(context)!.usage4),
                      ]
                    ),
                  ),
                  _border(),
                  Padding(
                    padding: const EdgeInsets.only(top: 24, left: 0, right: 0, bottom: 36),
                    child: SizedBox(
                      child: Text('version  ${VersionState.versionLoad()}',
                        style: const TextStyle(
                          fontSize: 10,
                        ),
                      ),
                    ),
                  ),
                ]),
              ),
            ),
          ),
        ),
        Padding(
          padding: const EdgeInsets.only(top: 10, left: 0, right: 0, bottom: 0),
          child: SizedBox(
            width: double.infinity,
            child: _adMob.getAdBannerWidget(),
          ),
        ),
      ]),
    );
  }
  //UIの仕切り用ボーダーライン
  Widget _border() {
    return Container(
      decoration: BoxDecoration(
        border: Border(
          top: BorderSide(
            color: Colors.grey.shade300,
            width: 1,
          ),
        ),
      ),
    );
  }
  //言語一覧表示
  TableCell _languageTableCell(int index) {
    return TableCell(
      child: RadioListTile(
        visualDensity: const VisualDensity(horizontal: VisualDensity.minimumDensity,vertical: VisualDensity.minimumDensity),
        contentPadding: EdgeInsets.zero,
        title: Text(ConstValue.languageCode.values.elementAt(index)),
        value: ConstValue.languageCode.values.elementAt(index),
        groupValue: _languageValue,
        onChanged: (String? value) {
          setState(() {
            _languageValue = value ?? '';
            _languageKey = ConstValue.languageCode.keys.elementAt(index);
          });
        },
        activeColor: ConstValue.colorUiActiveColor,
      ),
    );
  }

}

lib/version_state.dart

///
/// @author akira ohmachi
/// @copyright ao-system, Inc.
/// @date 2023-01-27
///
library;

class VersionState {

  static String _version = '';

  //バージョンを記録
  static void versionSave(String str) {
    _version = str;
  }
  //バージョンを返す
  static String versionLoad() {
    return _version;
  }

}

lib/l10n/app_bg.arb

{
	"@@locale":"bg",
	"@locale": {
		"description": "ブルガリア"
	},
    "setting": "Настройка",
    "showEhou": "Покажи Lucky Direction",
    "selectYear": "Изберете Година",
    "setCurrentYear": "Задайте избор на година на текущата година",
    "showBackImage": "Показване на фоново изображение",
    "soundVolume": "Сила на звука на звуковия ефект",
    "language": "език",
    "usage1": "Компас (насочена магнитна стрелка)",
    "usage2": "Ehoumaki (ролка за късмет) е традиционна храна, свързана със Setsubun, японски фестивал, празнуван на 3 февруари. То е особено популярно в региона Kansai. Смята се, че това ястие носи късмет, когато се яде с лице към посоката на късмета през тази година. Хората се събират, за да се насладят на Ehoumaki, а конкретната посока се обявява всяка година във връзка със Setsubun, насърчавайки консумацията на това специално суши руло.",
    "usage3": "",
    "usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_cs.arb

{
	"@@locale":"cs",
	"@locale": {
		"description": "チェコ"
	},
    "setting": "Nastavení",
    "showEhou": "Ukaž šťastný směr",
    "selectYear": "Vyberte rok",
    "setCurrentYear": "Nastavte výběr roku na aktuální rok",
    "showBackImage": "Zobrazit obrázek na pozadí",
    "soundVolume": "Hlasitost zvukového efektu",
    "language": "Jazyk",
    "usage1": "Kompas (směrová magnetická střelka)",
    "usage2": "Ehoumaki (role pro štěstí) je tradiční jídlo spojené s Setsubun, japonským festivalem, který se slaví 3. února. Obzvláště populární je v oblasti Kansai. Věří se, že toto jídlo přináší štěstí, když se sní ve šťastném směru toho roku. Lidé se scházejí, aby si pochutnali na Ehoumaki, a konkrétní směr je každoročně vyhlašován v souvislosti s Setsubun, který podporuje konzumaci této speciální sushi rolky.",
    "usage3": "",
    "usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_da.arb

{
	"@@locale":"da",
	"@locale": {
		"description": "デンマーク"
	},
    "setting": "Indstilling",
    "showEhou": "Vis Lucky Direction",
    "selectYear": "Vælg år",
    "setCurrentYear": "Indstil valg af år til indeværende år",
    "showBackImage": "Vis baggrundsbillede",
    "soundVolume": "Lydeffekt lydstyrke",
    "language": "Sprog",
    "usage1": "Kompas (retningsbestemt magnetisk nål)",
    "usage2": "Ehoumaki (lucky direction roll) er en traditionel mad, der er forbundet med Setsubun, en japansk festival, der fejres den 3. februar. Den er særlig populær i Kansai-regionen. Denne ret menes at bringe held, når den spises vendt mod den heldige retning det år. Folk samles for at nyde Ehoumaki, og den specifikke retning annonceres hvert år i forbindelse med Setsubun, hvilket tilskynder til forbruget af denne specielle sushirulle.",
    "usage3": "",
    "usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_de.arb

{
	"@@locale":"de",
	"@locale": {
		"description": "ドイツ"
	},
    "setting": "Einstellung",
    "showEhou": "Zeigen Sie die Glücksrichtung an",
    "selectYear": "Wählen Sie Jahr aus",
    "setCurrentYear": "Stellen Sie die Jahresauswahl auf das aktuelle Jahr ein",
    "showBackImage": "Hintergrundbild anzeigen",
    "soundVolume": "Lautstärke des Soundeffekts",
    "language": "Sprache",
    "usage1": "Kompass (Richtungsmagnetnadel)",
    "usage2": "Das Ehoumaki (Glücksrichtungsrolle) ist ein traditionelles Essen, das mit Setsubun, einem japanischen Fest, das am 3. Februar gefeiert wird, in Verbindung gebracht wird. Es ist besonders in der Kansai-Region beliebt. Es wird angenommen, dass dieses Gericht Glück bringt, wenn es in der Glücksrichtung des Jahres gegessen wird. Menschen versammeln sich, um Ehoumaki zu genießen, und die genaue Richtung wird jedes Jahr im Zusammenhang mit Setsubun bekannt gegeben, was zum Verzehr dieser besonderen Sushi-Rolle anregt.",
    "usage3": "",
    "usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_el.arb

{
	"@@locale":"el",
	"@locale": {
		"description": "ギリシャ"
	},
    "setting": "Σύνθεση",
    "showEhou": "Εμφάνιση Τυχερής Κατεύθυνσης",
    "selectYear": "Επιλέξτε Έτος",
    "setCurrentYear": "Ορίστε την επιλογή έτους σε τρέχον έτος",
    "showBackImage": "Εμφάνιση εικόνας φόντου",
    "soundVolume": "Ένταση ήχου εφέ",
    "language": "Γλώσσα",
    "usage1": "Πυξίδα (κατευθυντική μαγνητική βελόνα)",
    "usage2": "Το Ehoumaki (τυχερό ρολό κατεύθυνσης) είναι ένα παραδοσιακό φαγητό που συνδέεται με το Setsubun, ένα ιαπωνικό φεστιβάλ που γιορτάζεται στις 3 Φεβρουαρίου. Είναι ιδιαίτερα δημοφιλές στην περιοχή Kansai. Αυτό το πιάτο πιστεύεται ότι φέρνει καλή τύχη όταν τρώγεται απέναντι στην τυχερή κατεύθυνση εκείνης της χρονιάς. Ο κόσμος μαζεύεται για να απολαύσει το Εχουμάκι και η συγκεκριμένη κατεύθυνση ανακοινώνεται κάθε χρόνο σε σχέση με το Setsubun, ενθαρρύνοντας την κατανάλωση αυτού του ιδιαίτερου ρολού σούσι.",
    "usage3": "",
    "usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_en.arb

{
	"@@locale":"en",
	"@locale": {
		"description": "英語"
	},
	"setting": "Setting",
	"showEhou": "Show Lucky Direction",
	"selectYear": "Select Year",
	"setCurrentYear": "Set year selection to current year",
	"showBackImage": "Show Background image",
	"soundVolume": "Sound Effect Volume",
	"language": "Language",
	"usage1": "Compass (Directional Magnetic Needle)",
	"usage2": "The Ehoumaki (lucky direction roll) is a traditional food associated with Setsubun, a Japanese festival celebrated on February 3rd. It is particularly popular in the Kansai region. This dish is believed to bring good luck when eaten facing the lucky direction of that year. People gather to enjoy Ehoumaki, and the specific direction is announced each year in connection with Setsubun, encouraging the consumption of this special sushi roll.",
	"usage3": "",
	"usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_es.arb

{
	"@@locale":"es",
	"@locale": {
		"description": "スペイン"
	},
    "setting": "Configuración",
    "showEhou": "Mostrar dirección afortunada",
    "selectYear": "Seleccionar año",
    "setCurrentYear": "Establecer la selección de año en el año actual",
    "showBackImage": "Mostrar imagen de fondo",
    "soundVolume": "Volumen del efecto de sonido",
    "language": "Idioma",
    "usage1": "Brújula (aguja magnética direccional)",
    "usage2": "El Ehoumaki (rollo de dirección de la suerte) es una comida tradicional asociada con Setsubun, un festival japonés que se celebra el 3 de febrero. Es particularmente popular en la región de Kansai. Se cree que este plato trae buena suerte cuando se come mirando en la dirección de la suerte de ese año. La gente se reúne para disfrutar del Ehoumaki, y cada año se anuncia una dirección específica en relación con Setsubun, fomentando el consumo de este rollo de sushi especial.",
    "usage3": "",
    "usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_et.arb

{
	"@@locale":"et",
	"@locale": {
		"description": "エストニア"
	},
    "setting": "Seadistamine",
    "showEhou": "Näita õnnelikku suunda",
    "selectYear": "Valige Aasta",
    "setCurrentYear": "Määra aastavalikuks jooksev aasta",
    "showBackImage": "Näita taustapilti",
    "soundVolume": "Heliefekti helitugevus",
    "language": "Keel",
    "usage1": "Kompass (suunaline magnetnõel)",
    "usage2": "Ehoumaki (õnneliku suuna rull) on traditsiooniline toit, mis on seotud Jaapani festivali Setsubuniga, mida tähistatakse 3. veebruaril. See on eriti populaarne Kansai piirkonnas. Usutakse, et see roog toob õnne, kui süüakse selle aasta õnneliku suunaga. Inimesed kogunevad Ehoumakit nautima ja igal aastal kuulutatakse Setsubuniga seoses välja konkreetne suund, julgustades seda erilist sushirulli tarbima.",
    "usage3": "",
    "usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_fi.arb

{
	"@@locale":"fi",
	"@locale": {
		"description": "フィンランド"
	},
    "setting": "Asetus",
    "showEhou": "Näytä Lucky Direction",
    "selectYear": "Valitse Vuosi",
    "setCurrentYear": "Aseta vuosivalinta kuluvaksi vuodeksi",
    "showBackImage": "Näytä taustakuva",
    "soundVolume": "Äänitehosteen äänenvoimakkuus",
    "language": "Kieli",
    "usage1": "Kompassi (suuntaava magneettineula)",
    "usage2": "Ehoumaki (onnen suuntarulla) on perinteinen ruoka, joka liittyy Setsubuniin, japanilaiseen juhlaan, jota vietetään helmikuun 3. päivänä. Se on erityisen suosittu Kansain alueella. Tämän ruuan uskotaan tuovan onnea, kun sitä syödään sen vuoden onnensuunnassa. Ihmiset kokoontuvat nauttimaan Ehoumakista, ja tarkka suunta ilmoitetaan vuosittain Setsubunin yhteydessä kannustaen tämän erikoissushirullan nauttimiseen.",
    "usage3": "",
    "usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_fr.arb

{
	"@@locale":"fr",
	"@locale": {
		"description": "フランス"
	},
    "setting": "Paramètre",
    "showEhou": "Montrer la direction chanceuse",
    "selectYear": "Sélectionnez l'année",
    "setCurrentYear": "Définir la sélection de l'année sur l'année en cours",
    "showBackImage": "Afficher l'image d'arrière-plan",
    "soundVolume": "Volume des effets sonores",
    "language": "Langue",
    "usage1": "Boussole (aiguille magnétique directionnelle)",
    "usage2": "L'Ehoumaki (rouleau porte-bonheur) est un aliment traditionnel associé au Setsubun, une fête japonaise célébrée le 3 février. Il est particulièrement populaire dans la région du Kansai. Ce plat est censé porter chance lorsqu'il est consommé face à la direction porte-bonheur de cette année-là. Les gens se rassemblent pour déguster l'Ehoumaki, et une direction spécifique est annoncée chaque année en lien avec Setsubun, encourageant la consommation de ce rouleau de sushi spécial.",
    "usage3": "",
    "usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_hu.arb

{
	"@@locale":"hu",
	"@locale": {
		"description": "ハンガリー"
	},
    "setting": "Beállítás",
    "showEhou": "Szerencsés irány megjelenítése",
    "selectYear": "Válassza az Évet",
    "setCurrentYear": "Az évválasztás beállítása az aktuális évre",
    "showBackImage": "Háttérkép megjelenítése",
    "soundVolume": "Hangeffektus hangereje",
    "language": "Nyelv",
    "usage1": "Iránytű (iránytű mágneses tű)",
    "usage2": "Az Ehoumaki (szerencsés iránytekercs) egy hagyományos étel, amely a Setsubunhoz, a február 3-án ünnepelt japán fesztiválhoz kötődik. Különösen népszerű a Kansai régióban. Úgy tartják, hogy ez az étel szerencsét hoz, ha az adott év szerencsés irányába fordulva fogyasztják. Az emberek összegyűlnek, hogy élvezzék az Ehoumakit, és a konkrét irányt minden évben a Setsubun kapcsán hirdetik meg, ösztönözve ennek a különleges sushi tekercsnek a fogyasztását.",
    "usage3": "",
    "usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_it.arb

{
	"@@locale":"it",
	"@locale": {
		"description": "イタリア"
	},
    "setting": "Collocamento",
    "showEhou": "Mostra la direzione fortunata",
    "selectYear": "Seleziona Anno",
    "setCurrentYear": "Imposta la selezione dell'anno sull'anno corrente",
    "showBackImage": "Mostra immagine di sfondo",
    "soundVolume": "Volume dell'effetto sonoro",
    "language": "Lingua",
    "usage1": "Bussola (ago magnetico direzionale)",
    "usage2": "L'Ehoumaki (rotolo della direzione fortunata) è un piatto tradizionale associato al Setsubun, una festa giapponese celebrata il 3 febbraio, particolarmente popolare nella regione del Kansai: si ritiene che questo piatto porti fortuna se mangiato rivolto nella direzione fortunata di quell'anno. Le persone si riuniscono per godersi l'Ehoumaki e ogni anno viene annunciata una direzione specifica in relazione a Setsubun, incoraggiando il consumo di questo speciale rotolo di sushi.",
    "usage3": "",
    "usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_ja.arb

{
	"@@locale":"ja",
	"@locale": {
		"description": "日本"
	},
	"setting": "設定",
	"showEhou": "恵方表示",
	"selectYear": "年を選択",
	"setCurrentYear": "年選択を今年に設定",
	"showBackImage": "背景画像表示",
	"soundVolume": "効果音の音量",
	"language": "言語",
	"usage1": "コンパス(方位磁針)です。",
	"usage2": "恵方を示します。恵方巻(えほうまき)は、日本の節分(2月3日)に関連した伝統的な食べ物で、関西地方を中心に親しまれています。この料理は、その年の恵方を向いて食べることで幸運を呼ぶとされています。",
	"usage3": "",
	"usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_lt.arb

{
	"@@locale":"lt",
	"@locale": {
		"description": "リトアニア"
	},
    "setting": "Nustatymas",
    "showEhou": "Rodyti laimingą kryptį",
    "selectYear": "Pasirinkite metus",
    "setCurrentYear": "Nustatyti metų pasirinkimą į einamuosius metus",
    "showBackImage": "Rodyti foninį vaizdą",
    "soundVolume": "Garso efekto garsumas",
    "language": "Kalba",
    "usage1": "Kompasas (kryptinė magnetinė adata)",
    "usage2": "Ehoumaki (laimingos krypties ritinys) yra tradicinis maistas, susijęs su Setsubun – japonų švente, švenčiama vasario 3 d. Jis ypač populiarus Kanzajaus regione. Manoma, kad šis patiekalas atneš sėkmę, kai valgomas tų metų laiminga kryptimi. Žmonės susirenka pasimėgauti Ehoumaki, o konkreti kryptis kiekvienais metais skelbiama Setsubun, skatinant vartoti šį ypatingą sušių ritinį.",
    "usage3": "",
    "usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_lv.arb

{
	"@@locale":"lv",
	"@locale": {
		"description": "ラトビア"
	},
    "setting": "Iestatījums",
    "showEhou": "Parādiet laimīgo virzienu",
    "selectYear": "Izvēlieties Gads",
    "setCurrentYear": "Iestatīt gada atlasi uz pašreizējo gadu",
    "showBackImage": "Rādīt fona attēlu",
    "soundVolume": "Skaņas efekta skaļums",
    "language": "Valoda",
    "usage1": "Kompass (virziena magnētiskā adata)",
    "usage2": "Ehoumaki (laimīgā virziena rullītis) ir tradicionāls ēdiens, kas saistīts ar Setsubun — japāņu festivālu, kas tiek svinēts 3. februārī. Tas ir īpaši populārs Kanzai reģionā. Tiek uzskatīts, ka šis ēdiens nes veiksmi, ja to ēd tā gada laimīgajā virzienā. Cilvēki pulcējas, lai baudītu Ehoumaki, un konkrētais virziens tiek paziņots katru gadu saistībā ar Setsubun, mudinot lietot šo īpašo suši rullīti.",
    "usage3": "",
    "usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_nl.arb

{
	"@@locale":"nl",
	"@locale": {
		"description": "オランダ"
	},
    "setting": "Instelling",
    "showEhou": "Toon gelukkige richting",
    "selectYear": "Selecteer Jaar",
    "setCurrentYear": "Stel de jaarselectie in op het huidige jaar",
    "showBackImage": "Achtergrondafbeelding weergeven",
    "soundVolume": "Geluidseffectvolume",
    "language": "Taal",
    "usage1": "Kompas (directionele magnetische naald)",
    "usage2": "De Ehoumaki (geluksrichtingsbroodje) is een traditioneel gerecht dat geassocieerd wordt met Setsubun, een Japans festival dat gevierd wordt op 3 februari. Het is vooral populair in de regio Kansai. Er wordt aangenomen dat dit gerecht geluk brengt als het wordt gegeten met de blik in de geluksrichting van dat jaar. Mensen komen samen om van Ehoumaki te genieten, en de specifieke richting wordt elk jaar aangekondigd in verband met Setsubun, waardoor de consumptie van dit speciale sushibroodje wordt aangemoedigd.",
    "usage3": "",
    "usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_pl.arb

{
	"@@locale":"pl",
	"@locale": {
		"description": "ポーランド"
	},
    "setting": "Ustawienie",
    "showEhou": "Pokaż szczęśliwy kierunek",
    "selectYear": "Wybierz rok",
    "setCurrentYear": "Ustaw wybór roku na bieżący rok",
    "showBackImage": "Pokaż obraz tła",
    "soundVolume": "Głośność efektu dźwiękowego",
    "language": "Język",
    "usage1": "Kompas (kierunkowa igła magnetyczna)",
    "usage2": "Ehoumaki (bułka na szczęście) to tradycyjne jedzenie związane z Setsubun, japońskim świętem obchodzonym 3 lutego. Szczególnie popularne jest w regionie Kansai. Uważa się, że to danie przynosi szczęście, jeśli jest spożywane zwrócone w stronę szczęśliwego kierunku danego roku. Ludzie gromadzą się, aby delektować się Ehoumaki, a co roku ogłaszany jest konkretny kierunek w związku z Setsubun, zachęcając do spożycia tej specjalnej rolki sushi.",
    "usage3": "",
    "usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_pt.arb

{
	"@@locale":"pt",
	"@locale": {
		"description": "ポルトガル"
	},
    "setting": "Contexto",
    "showEhou": "Mostrar direção sortuda",
    "selectYear": "Selecione o ano",
    "setCurrentYear": "Definir a seleção do ano para o ano atual",
    "showBackImage": "Mostrar imagem de fundo",
    "soundVolume": "Volume do efeito sonoro",
    "language": "Linguagem",
    "usage1": "Bússola (agulha magnética direcional)",
    "usage2": "O Ehoumaki (rolo da direção da sorte) é um alimento tradicional associado ao Setsubun, um festival japonês celebrado em 3 de fevereiro. É particularmente popular na região de Kansai. Acredita-se que este prato traz boa sorte quando comido voltado para a direção da sorte daquele ano. As pessoas se reúnem para saborear o Ehoumaki, e a cada ano a direção específica é anunciada em conexão com o Setsubun, incentivando o consumo deste sushi roll especial.",
    "usage3": "",
    "usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_ro.arb

{
	"@@locale":"ro",
	"@locale": {
		"description": "ルーマニア"
	},
    "setting": "Setare",
    "showEhou": "Arată direcția norocoasă",
    "selectYear": "Selectați Anul",
    "setCurrentYear": "Setați selecția anului la anul curent",
    "showBackImage": "Afișați imaginea de fundal",
    "soundVolume": "Volumul efectului sonor",
    "language": "Limba",
    "usage1": "Busolă (ac magnetic direcțional)",
    "usage2": "Ehoumaki (lucky direction roll) este o mâncare tradițională asociată cu Setsubun, un festival japonez sărbătorit pe 3 februarie.Este deosebit de popular în regiunea Kansai.Acest fel de mâncare se crede că aduce noroc atunci când este consumat în fața direcției norocoase din acel an. Oamenii se adună pentru a savura Ehoumaki, iar direcția specifică este anunțată în fiecare an în legătură cu Setsubun, încurajând consumul acestui rulou special de sushi.",
    "usage3": "",
    "usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_ru.arb

{
	"@@locale":"ru",
	"@locale": {
		"description": "ロシア"
	},
    "setting": "Параметр",
    "showEhou": "Показать счастливое направление",
    "selectYear": "Выберите год",
    "setCurrentYear": "Установить выбор года на текущий год",
    "showBackImage": "Показать фоновое изображение",
    "soundVolume": "Громкость звукового эффекта",
    "language": "Язык",
    "usage1": "Компас (направленная магнитная стрелка)",
    "usage2": "Эхумаки (ролл счастливого направления) — традиционное блюдо, связанное с Сэцубун, японским праздником, который отмечается 3 февраля. Оно особенно популярно в регионе Кансай. Считается, что это блюдо приносит удачу, если его есть лицом в сторону удачи этого года. Люди собираются, чтобы насладиться Эхумаки, и каждый год в связи с Сэцубуном объявляется конкретное направление, поощряющее потребление этого особого суши-ролла.",
    "usage3": "",
    "usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_sk.arb

{
	"@@locale":"sk",
	"@locale": {
		"description": "スロバキア"
	},
    "setting": "Nastavenie",
    "showEhou": "Ukážte šťastný smer",
    "selectYear": "Vyberte rok",
    "setCurrentYear": "Nastavte výber roka na aktuálny rok",
    "showBackImage": "Zobraziť obrázok na pozadí",
    "soundVolume": "Hlasitosť zvukových efektov",
    "language": "Jazyk",
    "usage1": "Kompas (smerová magnetická ihla)",
    "usage2": "Ehoumaki (roletka so šťastným smerom) je tradičné jedlo spojené s japonským sviatkom Setsubun, ktorý sa oslavuje 3. februára. Obľúbené je najmä v regióne Kansai. Verí sa, že toto jedlo prináša šťastie, keď sa zje v tom roku šťastným smerom. Ľudia sa stretávajú, aby si vychutnali Ehoumaki, a konkrétny smer sa každoročne oznamuje v súvislosti so Setsubunom, ktorý podporuje konzumáciu tejto špeciálnej sushi rolky.",
    "usage3": "",
    "usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_sv.arb

{
	"@@locale":"sv",
	"@locale": {
		"description": "スウェーデン"
	},
    "setting": "Miljö",
    "showEhou": "Visa Lucky Direction",
    "selectYear": "Välj år",
    "setCurrentYear": "Ställ in årsval till innevarande år",
    "showBackImage": "Visa bakgrundsbild",
    "soundVolume": "Ljudeffektvolym",
    "language": "Språk",
    "usage1": "Kompass (riktad magnetisk nål)",
    "usage2": "Ehoumaki (lucky direction roll) är en traditionell mat förknippad med Setsubun, en japansk festival som firas den 3 februari. Den är särskilt populär i Kansai-regionen. Den här rätten tros ge lycka när den äts mot den lyckliga riktningen det året. Människor samlas för att njuta av Ehoumaki, och den specifika riktningen tillkännages varje år i samband med Setsubun, vilket uppmuntrar konsumtionen av denna speciella sushirulle.",
    "usage3": "",
    "usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_th.arb

{
	"@@locale":"th",
	"@locale": {
		"description": "タイ"
	},
    "setting": "การตั้งค่า",
    "showEhou": "แสดงทิศทางนำโชค",
    "selectYear": "เลือกปี",
    "setCurrentYear": "ตั้งค่าการเลือกปีเป็นปีปัจจุบัน",
    "showBackImage": "แสดงภาพพื้นหลัง",
    "soundVolume": "ระดับเสียงเอฟเฟกต์",
    "language": "ภาษา",
    "usage1": "เข็มทิศ (เข็มแม่เหล็กทิศทาง)",
    "usage2": "เอโฮมากิ (ม้วนทิศนำโชค) เป็นอาหารแบบดั้งเดิมที่เกี่ยวข้องกับ Setsubun ซึ่งเป็นเทศกาลของญี่ปุ่นที่เฉลิมฉลองในวันที่ 3 กุมภาพันธ์ เป็นที่นิยมโดยเฉพาะในภูมิภาคคันไซ เชื่อกันว่าอาหารจานนี้จะนำโชคดีมาเมื่อรับประทานหันหน้าไปทางทิศนำโชคของปีนั้น ผู้คนมารวมตัวกันเพื่อเพลิดเพลินกับเอโฮมากิ และจะมีการประกาศทิศทางที่เฉพาะเจาะจงในแต่ละปีเกี่ยวกับเซทสึบุน เพื่อกระตุ้นให้เกิดการบริโภคซูชิโรลสูตรพิเศษนี้",
    "usage3": "",
    "usage4": "",

	"dummy": "dummy"
}

lib/l10n/app_zh.arb

{
	"@@locale":"zh",
	"@locale": {
		"description": "中国"
	},
    "setting": "环境",
    "showEhou": "显示幸运方向",
    "selectYear": "选择年份",
    "setCurrentYear": "将年份选择设置为当前年份",
    "showBackImage": "显示背景图片",
    "soundVolume": "音效音量",
    "language": "语言",
    "usage1": "指南针(定向磁针)",
    "usage2": "Ehoumaki(幸运方向卷)是与 2 月 3 日庆祝的日本节日“节分”相关的传统食品。它在关西地区特别受欢迎。人们相信,面对当年的幸运方向食用这道菜会带来好运。人们聚集在一起享用江丰卷,每年都会与节分一起宣布具体方向,鼓励消费这种特殊的寿司卷。",
    "usage3": "",
    "usage4": "",

	"dummy": "dummy"
}