iOS / Android 用のローカライズ文字列ファイルを生成するツール「strgen」
iOS / Android のローカライズ文字列ファイルを一括で生成するツールstrgen(Python)を作った。
PyPI に登録してあるので、 pip でインストールできます。
概要
多言語情報を記載した CSV と、設定を記載した YAML ファイルを入力として、以下のファイルを出力する。
- iOS 用ファイル
- 各言語用の
Localized.strings
- ローカライズのキーが定義されている Swift ファイル(
LocalizedStrings.swift
)
- 各言語用の
- Android 用ファイル
- 各言語用の
strings.xml
- 各言語用の
strgen を使うメリット
一元管理できる
iOS / Android のローカライズファイルのソースが、単一の CSV になり、多言語が一元管理できる。
多言語更新のミスが発生しにくい
ツールで生成したファイルをプロジェクトに反映させるだけなので、ファイル(Localized.strings, strings.xml)を直接編集するのに比べ、ミスが発生しにくい。
iOS のローカライズの効率がよくなる
hello
というキーでローカライズ文字列が存在する場合、 iOS はキーを文字列で指定してローカライズ文字列を得るので、以下のようになる。
NSLocalizedString("hello", comment: "")
しかし、これは存在していないキーも指定できる問題がある。
たとえば、以下のようにキー指定をミスした場合、ビルド時には分からず、ミスがわかるのは実行時に確認した時だ(ローカライズ文字列が正しく表示されないので)
NSLocalizedString("hellow", comment: "")
この問題の対応として strgen は iOS の多言語ファイルを生成する時に、一緒にキーを列挙した swift ファイル(LocalizedStrings.swit)も作成する。
import Foundation class LocalizableStrings { enum Key: String { case hello = "hello" } }
この swift ファイルからキー定義を参照するようにすると、ローカライズのコーディングの際に、ビルド時点でミスに気付けるので、効率がよくなる。
NSLocalizedString(LocalizableStrings.Key.hello.rawValue, comment: "")
strgen を試してみる
サンプルで動作を確認できます。
インストール
まず、 pip で strgen をインストールします。
$ pip install strgen
これで、コマンドラインから strgen を実行できるようになる。
$ which strgen
/usr/local/bin/strgen
サンプルを動作させてみる
- プロジェクトを clone します。
$ git clone https://github.com/daisuke-t-jp/strgen
- カレントディレクトリを clone したプロジェクト内の
strgen/sample
フォルダに変更します。 - 以下のコマンドを実行。
$ strgen strgen.yml
build
フォルダを確認します。
使い方
そのほかの使い方、YAML ファイルの仕様などは、README を参照してください。
Python パッケージ作成に関する情報まとめ
Python パッケージ作成、PyPI(パイ・ピーアイ) への登録などに役立つ情報を、まとめる。
setup.py
だけ使用するパターン、setup.cfg
も使用するパターン、__init__.py
に多くの役割を持たせるパターン/ほとんど役割を持たせないパターン、などパッケージ作成に関してさまざま選択肢があるので、いろいろな例を見ておくと良い。
関連公式ドキュメント
- Python モジュールの配布 — Python 3.9.1rc1 ドキュメント
- 2. setup スクリプトを書く — Python 3.9.1rc1 ドキュメント
- 6. モジュール — Python 3.9.1rc1 ドキュメント
参考情報
- Python Packaging User Guide — Python Packaging User Guide ドキュメント
- 【Techの道も一歩から】第21回「setup.pyを書いてpipでインストール可能にしよう」 - Sansan Builders Blog
- PythonのCLIパッケージの作り方 - karakaram-blog
- Pythonのパッケージ周りのベストプラクティスを理解する - エムスリーテックブログ
- setuptools: Pythonパッケージ作成 - Heavy Watal
- Pythonのパッケージングのベストプラクティスについて考える2018 - 朝日ネット 技術者ブログ
- Pythonでグローバルコマンドを含んだパッケージを作る - Qiita
- 自作のPythonパッケージをPyPIに登録してpip install可能にする - Qiita
参考になる Python パッケージ(OSS)
- GitHub - VaasuDevanS/cowsay-python: The famous cowsay 🐮 for GNU/Linux is now available for python 🐍
- 非常にシンプルなパッケージ(CLI の参考にもなる)
- GitHub - pypa/twine: Utilities for interacting with PyPI
config.cfg
の書き方が参考になる(CLI の参考にもなる)
- GitHub - jazzband/django-redis: Full featured redis cache backend for Django.
- GitHub - yaml/pyyaml: Canonical source repository for PyYAML
パッケージのインストールテスト
パッケージを作ったらインストールして試してみる
開発用
開発中のパッケージは、こちらの方法でインストールしてテストする。
$ python setup.py develop # もしくは $ pip install -e .
配布用
# 配布用パッケージの作成 # これで dist/ 以下にパッケージ(tar.gz)ができる $ python setup.py sdist # 配布用パッケージのインストール $ pip install dist/*
パッケージ情報の確認
$ pip show <パッケージ名>
アンインストール
$ pip uninstall <パッケージ名>
PyPI への登録
登録するためのツール twine
が入っていないならインストールする。
$ pip install twine
登録。
$ twine upload --repository pypi dist/*
iOS でパラパラ漫画のような見た目のインジケーターを作った
everysing というカラオケのアプリで、読み込み中に表示されるインジケーターがパラパラ漫画のようになっていて、キュートな感じがしてよい。(マイクやヘッドフォンのアイコンが表示される)
この UI を再現したく、パラパラとアニメするインジケータを作ってみた。
↓こんな感じに画像を設定すれば、パラパラアニメで表示される。
import ParaParaIndicator class ViewController: UIViewController { let paraparaIndicator = ParaParaIndicator() override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. // Images for flipping paraparaIndicator.images = [ UIImage(named: "camel")!.withRenderingMode(.alwaysTemplate), UIImage(named: "deer")!.withRenderingMode(.alwaysTemplate), UIImage(named: "elephant")!.withRenderingMode(.alwaysTemplate), UIImage(named: "giraffe")!.withRenderingMode(.alwaysTemplate), UIImage(named: "kangaroo")!.withRenderingMode(.alwaysTemplate), UIImage(named: "mouse")!.withRenderingMode(.alwaysTemplate), UIImage(named: "rhino")!.withRenderingMode(.alwaysTemplate), ] // Indicator frame paraparaIndicator.frame.size.width = 100 paraparaIndicator.frame.size.height = 100 paraparaIndicator.center = self.view.center // Tint color paraparaIndicator.tintColor = .cyan // Flip interval paraparaIndicator.timeInterval = 0.3 // Hide when stopped paraparaIndicator.hidesWhenStopped = true // Start animation paraparaIndicator.startAnimating() // Stop animation // paraparaIndicator.stopAnimating() self.view.addSubview(paraparaIndicator) } }
なお UIActivityIndicatorView
Like で扱えるように、以下のメソッドを実装し、インターフェースを似せてある。
- hideWhenStopped
- isAnimating
- startAnimating
- stopAnimating
macOS 10.15 から有効な EndpointSecurity API(SystemExtension.framework)
https://developer.apple.com/jp/system-extensions/
macOS 10.15 から、従来のカーネル拡張(KEXT)を使わずに、ユーザーランドで動作するソフトでシステムイベントを監視(おそらくイベントの許可/禁止も)できるようになった。
https://developer.apple.com/contact/request/system-extension/
まず Apple に SystemExtension.framework / EndpointSecurity API の使用リクエストを出し、許可される必要がある。
https://developer.apple.com/documentation/endpointsecurity
プロジェクトで Endpoint Security API を使用するには、以下の2つをリンクする。
- SystemExtension.framwork
- libEndpointSecurity.tdb
entitlements に com.apple.developer.endpoint-security.client = YES を設定する。
※Apple に API リクエストが許可されていないと、アプリがただしく起動しない。
従来の KEXT を使用してシステム監視(アンチウィルスソフトなど)する場合より SystemExtension.framework を使用するメリット
- Kernel extension で機能を実現した場合、ソフトはカーネルランドで実行されるため、ソフトの処理が遅いと OS 全体も遅くなってしまうなど OS の安定性に関わる現象が起きる。その分、実装もシビアになる。
- ユーザランド実行になるとここが、そこまでシビアではなくなる?
- Kernel extension 由来のセキュリティ問題がある場合、カーネル空間でその問題は発生するので OS デベロッパ(Apple)、ソフトデベロッパの責務の線引きが不明瞭になる。
不明な点
https://developer.apple.com/documentation/endpointsecurity/client?language=objc
GitHub Action の Private / Public リポジトリの制限
GitHub Actionsの支払いについて - GitHub ヘルプ
Public リポジトリ
GitHub Actions の制限はない
Private リポジトリ
GitHub Actions の実行時間とストレージに制限がある。
アカウントに存在するすべての Private リポジトリの実行時間、ストレージ使用量の合算が制限の対象。個々のリポジトリごとに制限が計算されるわけではない。
- Free アカウントの場合
- ストレージ : 500 MB
- 実行時間 : 2,000分(月)
- Pro アカウントの場合
- ストレージ : 1 GB
- 実行時間 : 3,000分(月)
Private リポジトリにおける GitHub の Actions の使用状況(利用時間とストレージ使用量)はユーザアカウントから確認できる。
GitHub Actions の使用状況を表示する - GitHub ヘルプ
制限を超えて使用したい場合は、料金支払いが必要になる。
まとめ
GitHub ワークフローで環境変数、シークレットな情報を使用する
これは 2020/05 時点の情報をもとにした記事なので、最新では事情が変わっている可能性を留意すること。
ワークフロー内で使用できる環境変数
たとえば GITHUB_REPOSITORY
(所有者とリポジトリの名前 octocat/Hello-World
など)がある。
API キーなどシークレット情報の扱い
暗号化されたシークレットの作成と保存 - GitHub ヘルプ
ある Web API を呼び出すのに必要な API キーがあったとして、それをコード中にそのまま記載してしまうと API キーの漏洩になってしまう。これを避けるため、シークレット情報は GitHub に設定して秘匿して使用することができる。
シークレット情報は Organization / Repository ごとに設定することができる。
設定したシークレット情報は、以下のようにワークフローで参照することができる。
steps: - shell: bash env: SUPER_SECRET: ${{ secrets.SuperSecret }} run: | example-command "$SUPER_SECRET"
GitHub ワークフローを使って、プロジェクトを定期実行し、成果物をデプロイする(Python)
GitHub ワークフローを使ってプロジェクトの定期実行→成果物をデプロイする方法を調べたのでまとめる。
これは 2020/05 時点の情報をもとにした記事なので、最新では事情が変わっている可能性を留意すること。
目的
GitHub ワークフロー / アクションの意味
ワークフロー
ワークフローとは、GitHubで任意のプロジェクトをビルド、テスト、パッケージ、リリース、またはデプロイするためにリポジトリで設定できる、カスタムの自動プロセスです。 ワークフローを使用すると、豊富なツールとサービスでソフトウェア開発のライフサイクルを自動化できます。
「ワークフロー」に記述した内容で、ビルドやテスト、リリース、デプロイが自動化できるようになる。
ワークフロー自体は .github/workflow の下に yml ファイルで記述する。
アクション
https://help.github.com/ja/actions/getting-started-with-github-actions/about-github-actions
GitHub Actionsは、コードを保存するのと同じ場所でソフトウェア開発のワークフローを自動化し、プルリクエストやIssueで協力することを支援します。 個々のタスクを書き、アクションを呼び出し、それらを組み合わせてカスタムのワークフローを作成できます。
「アクション」は「ワークフロー」を構成する単位となる。
どんなアクションがあるかは Markerplace で確認できる。
GitHub Marketplace · Actions to improve your workflow · GitHub
たとえば git リポジトリからチェックアウトするアクション「Checkout v2」がある。
Checkout · Actions · GitHub Marketplace · GitHub
この Checkout をワークフロー内で使用するには、以下のように記述する。
name: workflow-name # リポジトリに Push したタイミングでワークフローを実行する on: [push] jobs: build: name: workflow-job runs-on: ubuntu-latest steps: # リポジトリをチェックアウトする - name: Checkout uses: actions/checkout@v2 # チェックアウトされたリポジトリで、ビルド、テスト、リリース、デプロイ、などをする。
その他
- GitHubの新機能「GitHub Actions」で試すCI/CD | さくらのナレッジ
- ワークフロー、アクションの概念がわかりやすく書いている
GitHub リポジトリのプロジェクトを定期実行する(Python)
今回のサンプル
GitHub - daisuke-t-jp/jma-hazard-xml2json
今回作成したリポジトリはこれになる。(Python プロジェクト)
この Python スクリプトは気象庁で提供されている災害情報(XML)を取得して JSON フォーマットに変換して、ファイルに保存する、ということやっている。
気象庁 | 気象庁防災情報XMLフォーマット形式電文(PULL型)
requirements.txt
Python スクリプトに必要な外部パッケージを requirements.txt ファイルを作成し、そこに記載する。
今回は XML を Python の辞書として扱うために xmltodict を requirements.txt に追加する。
xmltodict
ワークフローを作成する
ローカルでスクリプトの動作が確認出来たら GitHub ワークフローを作成して GitHub 上でも動作するようにする。
今回のワークフローは以下の機能にする
- 定期実行したい(10分に1回)
- 成果物である JSON ファイルを保存したい
yaml で記載したワークフローは以下になる。
# ワークフローの名前 name: cron-deploy # ワークフローの実行タイミング # この場合は 10 分に 1 回 # # cron のフォーマットは以下が参考になる # http://manpages.ubuntu.com/manpages/trusty/ja/man5/crontab.5.html on: schedule: - cron: '*/10 * * * *' # ジョブの記述 jobs: # job_id は "build" build: # ジョブの名前(GitHub 上で表示される) name: deploy # Ubuntu で実行する # https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idruns-on runs-on: ubuntu-latest # ジョブのステップ steps: - name: Checkout # チェックアウト uses: actions/checkout@v2 - name: Setup Python 3.8 # Python のセットアップ uses: actions/setup-python@v1 with: python-version: 3.8 - name: Install dependencies # Python 外部パッケージをインストール run: | python -m pip install --upgrade pip pip install -r requirements.txt - name: Run script # Python スクリプトを実行する run: | python jma-hazard-xml2json.py - name: Deploy # gh-pages ブランチに成果物をデプロイする uses: peaceiris/actions-gh-pages@v3 with: github_token: ${{ secrets.GITHUB_TOKEN }} publish_dir: ./json
このワークフローを GitHub にコミットすると、ただしく10分ごとに gh-pages ブランチにデプロイされることが確認出来た。(前のファイルは上書きされる)