at backyard

Color my life with the chaos of trouble.

Agreeing to the Xcode/iOS license requires admin privileges, please run “sudo xcodebuild -license” and then retry this command.

Xcodeを最新にアップデートしたあとに、git コマンドを叩いたら、下記のような表示が出た

Agreeing to the Xcode/iOS license requires admin privileges, please run “sudo xcodebuild -license” and then retry this command.

テキストの通り、

sudo xcodebuild -license

と、打っても良さそうだったが、自分の場合はXcode立ち上げて、出てきたライセンス表示に対してAgreeすることで問題なく通過した。

よく遭遇する表示のようだったが、自分はあんまり記憶になったので一応メモしておく。
(たぶん忘れているだけかも)

ステインド、かっこよい

初めて聴いた。
ニルヴァーナを始めとするUSオルタナを感じさせる殺気立ちながらもどこかメロディックなヴォーカルラインと、メランコリックでダークでヘヴィなハードロックという感じでかっこよかった!

Dysfunction

Dysfunction

  • ステインド
  • ハードロック
  • ¥1630
music.apple.com

CircleCIでdocker imageのバージョンを上げたときに、default-mysql-clientのインストールでエラーになった際の対応備忘録

CircleCIで使用しているDocker imageのバージョンを上げたら、default-mysql-client をインストールする箇所でエラーになりました。

最初色々とネットの記事を見ながら、何度か試行錯誤しつつ悩んでいましたが、CircleCI で提供されている Docker Image をローカルにpullして、実際に動かしている CircleCI の設定と照らし合わせながら手作業でデバッグ・実行してみることで問題はすぐに解決しました。

ちなみに私がぶち当たった問題の対応としては、default-mysql-clientのインストールコマンドを実行する前にsudo apt-get updateを行えばよいだけでした。

CircleCIが提供しているDocker Image

下記のリンク先で確認できます。

https://hub.docker.com/u/circleci

例えば下記のような形で試せます。
(下の例ではnodeDocker imagepullしています)

docker pull circleci/node:{試したいversion}
docker run -t -i {pullしてきたIMAGE ID} /bin/bash

あとはdockerコンテナの中で実際にコマンドを叩きながら、試していけばOK

また、geohotが面白そうな動画を出していた。checkm8を用いて、iPhoneをハックする(書きかけポスト)

本題の前に、イバラキングのごじゃっぺラジオZについて

昨日の放送を聞いていただいた皆様、ありがとうございました!
twitterハッシュタグ#gojaradiでも感想を色々呟いていただけて、とても嬉しかったです。

twitter.com

また、イバラキングさんのページでも紹介していただいています。嬉しい!
ここに写っている写真は、公開収録日に撮影されたもの📷

www.ibaraking.com

ラヂオでも話したとおり、現在はイバラキングさんとのコラボ曲や、アルバムに向けた楽曲制作をガンガン進めております。
実は今日もB/Wメンツでレコーディングをしていました。
完成したら報告させてもらうのでぜひぜひ聴いてください😊

geohotがcheckm8を用いて、iPhoneをハックする,,,らしい?(書きかけポスト)

話は変わり、、、

geohotこと、George Hotzが新しい動画を公開していた。

www.youtube.com

checkm8を用いて、iPhoneをハックする動画のようだ。
(私はまだこの動画を見ていないので、動画の概要や飛ばし飛ばしで動画を見てこれを書いている。誤っていたら修正する)

checkm8については、WIREDやEngadgetの記事などを読んで概要を理解した。
そういえば数日前にiPhoneのジェイルブレイク関連の記事を目にしていたなーと思いつつ、あまり気にせず通り過ぎてしまっていたが、これのことだったのか。

wired.jp

japanese.engadget.com

WIREDの記事を引用させてもらう。

セキュリティ研究者のaxi0mXが「Github」に公開したエクスプロイトコードは、「checkm8」と呼ばれる。このコードは、アップルの独自チップである「A5」から「A11」までのチップセットを搭載したすべてのアップル端末、つまり「iPhone 4S」から「iPhone X」にいたるまでのiPhone全モデルに影響する。

実際にGeorge Hotzの動画や、WIREDの記事でも書かれているセキュリティ研究者のaxi0mXが「Github」に公開したエクスプロイトコードというのは下記になる。

github.com

このポストは書きかけのため、geohotの動画を見た段階で修正する可能性があることをここに記載しておく。

Reactアプリでのi18n対応(国際化/多言語対応)にi18nextを使ってみる

これはi18n対応のために i18nextreact-i18next を使ってみた備忘録となる。

目次

Reactアプリでのi18n対応(国際化/多言語対応)にi18nextを使ってみる

仕事で多言語対応をすることになり、i18nextを使うことにした。

Introduction - i18next documentation

Introduction - react-i18next documentation

react-intlとi18next

ちなみに react i18n 対応 で検索すると、なんと驚いたことに過去にQiitaに書いた自分の記事が一番目にヒットした(2019年9月時点)。

qiita.com

2019年9月時点で 16イイね がついているし、私にしては大健闘な状況である。
QiitaのSEO効果の偉大さを改めて思い知った。

こちらの記事では react-intl を使用しており、一応の使い方は理解したつもりだが、なぜ今回 i18next を使うことにしたかというと、うちの会社の別のサービスで既に導入実績があるからだ。
私が勤めている会社は、基本的に私以外は皆 凄腕エンジニアばかりで(もちろん、これはお世辞ではない)、 多言語対応周りの実装のレビューをしたりしながら、ふむふむこうやって使うのか、なるほどなーといつも勉強させてもらっていた。
そうこうしているうちに自分がメインで担当しているサービスでも一部多言語対応をしていくことになったため、既に皆が触っている i18next のほうがメンテナンスもしやすいし、社内に知見もたまってきているというわけで、こちらを導入することにしたというわけである。

というわけで、これは i18next を使ってみた、的な備忘録となる。

実際の仕事で使うやり方とは多少異なってくると思うが、自分の理解を深めるために、一通り触ってみたメモをこちらに残しておく。

サンプルアプリの雛形生成

create-react-appを使ってサンプルアプリの雛形を作成していく

npx create-react-app react-i18next-sample
cd react-i18next-sample
yarn start

create-react-appでブラウザが勝手に立ち上がらないようにする

ちなみに私はcreate-react-appyarn startしたときに勝手にブラウザが立ち上がる挙動が許せない質なので、下記のようにpackage.jsonを書き換えている。

diff --git a/package.json b/package.json
index 52a2f12..0730227 100644
--- a/package.json
+++ b/package.json
@@ -8,7 +8,7 @@
     "react-scripts": "3.1.2"
   },
   "scripts": {
-    "start": "react-scripts start",
+    "start": "BROWSER=none react-scripts start",
     "build": "react-scripts build",
     "test": "react-scripts test",
     "eject": "react-scripts eject"

これらの設定は下記に記述がある。

Advanced Configuration | Create React App

react-i18nextのセットアップ

ここからreacti18nextを使っていくための設定を行っていく。 これらの記述はだいたい下記のドキュメントを読んでいけば、わかるようになっている。

Getting started - i18next documentation

Getting started - react-i18next documentation

実際の実装については下記が参考になる

react-i18next/example/react at master · i18next/react-i18next · GitHub

一つだけ注意点。
自分がここから書いていく記述では、 SSR は考慮しないものとしていることを先に書いておく

yarn add i18next react-i18next 

i18n.js というファイルを作成する

import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';

const resources = {
  en: {
    translation: {
      'Learn React': 'Learn React'
    }
  },
  ja: {
    translation: {
      'Learn React': 'Reactを学ぶ'
    }
  }
};

i18n.use(initReactI18next).init({
  resources,
  fallbackLng: 'en',
  debug: true,

  interpolation: {
    escapeValue: false
  }
});

export default i18n;

HOCで使う場合はwithTranslationを使う

HOCを使う場合は withTranslation を用い、下記のようにしてi18nextの機能を使う

src/App.jsを下記のように書き換える

import React from 'react';
import logo from './logo.svg';
import './App.css';
import './i18n';
import { withTranslation } from 'react-i18next';

function App({ t }) {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          {t('Learn React')}
        </a>
      </header>
    </div>
  );
}

export default withTranslation()(App);

i18n.js内のfallbackLng: 'en'fallbackLng: 'ja'に書き換えることで言語が変わるのが確認できる。

hookで使う場合はuseTranslationを使う

hookで使う場合は useTranslation を使う。
上のサンプルと見比べてみると、使い方の違いがより分かるかと思う。

import React from 'react';
import logo from './logo.svg';
import './App.css';
import './i18n';
import { useTranslation } from 'react-i18next';

function App() {
  const { t, i18n } = useTranslation();
  //  下記のような書き方でもOK
  //  const [ t, i18n ] = useTranslation();

  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          {t('Learn React')}
        </a>
      </header>
    </div>
  );
}

export default App;

namespacesについて

ちなみにここまでしれっと translation という namespacesを使ってきたが、ここについては下記のドキュメントが参考になるかと思う。

Namespaces - i18next documentation

i18nextのnamespaceについてだが、小規模なプロジェクトであればすべてのテキストを一つのファイルに纏めて利用する形で事足りると思うが、大規模なサービスを運用したい場合はそうも言ってられなくなる。
そこでnamespaceを区切って、必要なテキストだけを読み込んでいこうということになる。

当然全てのテキストファイルが一度に読まれなくなるので読み込み時間の短縮などにもつながる。

ただ、namespaceを分けることによって、テキストの管理コストは上がるため、そこも考えてプロジェクト内で慎重に検討していったほうが良さそうというのが個人的な考え。

ドメインごとのテキストと共通で利用するテキストなど、どういう考え方で分けていくか?などを考えていく必要がある。

ちなみに i18next の公式サイトでは、下記のような分け方で分けているという書かれている。参考にしてみるのも良いかも。

common.json -> あらゆる場所で再利用されるもの、例えばボタンのラベル「save」や「cancel」など。
validation.json -> すべての検証テキスト
glossary.json -> テキストの中で一貫して使われて欲しい単語

https://www.i18next.com/principles/namespaces#semantic-reasons

translation というnamespaceの挙動について

translation はdefaultで利用されるnamespaceとなる。

namespaceが必要がない場合は translation というnamespaceがルートに位置する形となる。

例えば、このtranslation というnamespaceがない場合、i18next自体が機能しなくなる。

例として、下記のような構成の場合、動かない。 (日本語の言語ファイルは割愛)

{
  "Learn React": "Learn React",
  "Save to Reload text": "Edit <1>{{filename}}</1> and save to reload."
}
import en from './en/translation';
import ja from './ja/translation';

export default {
  en,
  ja
};
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import resources from './locales/resources';

i18n.use(initReactI18next).init({
  resources,
  fallbackLng: 'en',
  debug: true,

  interpolation: {
    escapeValue: false
  }
});

export default i18n;

この状態では動かない。

下記のように translation をルートに持ってくることで動くことが確認できる。

{
  "translation": {
    "Learn React": "Learn React",
    "Save to Reload text": "Edit <1>{{filename}}</1> and save to reload."
  }
}

実際に動かすときは下記のように呼び出すことになる。

// 呼び出すとき
t('Learn React')

この挙動からも translation がルートには必要であることが分かる。

次はこの translation を別の namespace1 というnamespaceに変えてみる。

すると呼び出し方が変わる。

{
  "namespace1": {
    "Learn React": "Learn React",
    "Save to Reload text": "Edit <1>{{filename}}</1> and save to reload."
  }
}

呼び出すときはこのnamespace1を込みで呼び出す必要がある。
(勿論この例はあくまでresourceファイルをそのままi18next側に読み込ませているからなわけで、読み込ませ方によって異なる呼び出し方になると思う)

// 呼び出すとき頭にnamespaceを指定する
t('namespace1:Learn React')

さらには上の状態にルートに translation を持ってくる

{
  "translation": {
    "namespace1": {
      "Learn React": "Learn React",
      "Save to Reload text": "Edit <1>{{filename}}</1> and save to reload."
    }
  }
}

この場合呼び出し方が下記のように変わってくる。

t('namespace1.Learn React')

以上のような挙動だが、たぶんここらへんで実装しているような気がするので、個人的なメモとして残しておく。

https://github.com/i18next/i18next/blob/master/src/ResourceStore.js#L36-L50

またこのような挙動については、ドキュメントの下記のページにも記載があるので、そちらを熟読したほうが本質的な理解に繋がりそう。

https://www.i18next.com/translation-function/essentials#accessing-keys-in-different-namespaces

Namespaces - i18next documentation

translationを言語のテキストファイルに含めたくない場合

このあとのサンプルにも登場させる書き方でいけば、言語テキストを格納するjsonファイルに translation を含める必要はなくなる。
(こちらについては 翻訳した言語の管理方法 という項目に書いている)

かんたんなサンプルを下記に記載する。

{
  "namespace1": {
    "Learn React": "Learn React",
    "Save to Reload text": "Edit <1>{{filename}}</1> and save to reload."
  }
}

下記のように言語ファイルは一つに予めまとめておくようにして、その後まとめたこれらのresourceをi18nextの初期化処理時に食わせる流れとする。

import enTranslation from './en/translation';
import jaTranslation from './ja/translation';

export default {
  en: {
    translation: enTranslation
  },
  ja: {
    translation: jaTranslation
  }
};
import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import resources from './locales/resources';

i18n.use(initReactI18next).init({
  resources,
  fallbackLng: 'en',
  debug: true,

  interpolation: {
    escapeValue: false
  }
});

export default i18n;

という形でセットすることで、下記のように呼び出すことが可能となる。

t('namespace1.Learn React')

言語を切り替える機能を実装する

i18n.changeLanguage という関数が用意されているので、こちらで切り替えを実装できる。 (雑なサンプルで恐縮である)

import React from 'react';
import logo from './logo.svg';
import './App.css';
import './i18n';
import { withTranslation, Trans } from 'react-i18next';

function changeLanguage(i18n, lang) {
  i18n.changeLanguage(lang);
}

function App({ t, i18n }) {
  const filename = 'src/App.js';

  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          <Trans i18nKey="Save to Reload text">
            Edit <code>{{ filename }}</code> and save to reload.
          </Trans>
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          {t('Learn React')}
        </a>
        <div>
          <p>Change Language</p>
          <button onClick={() => changeLanguage(i18n, 'en')}>en</button>
          <button onClick={() => changeLanguage(i18n, 'ja')}>ja</button>
        </div>
      </header>
    </div>
  );
}

export default withTranslation()(App);

f:id:shinshin86:20190926084817g:plain

翻訳した言語の管理方法

ここでは localesというディレクトリを作り、その配下に各種言語ごとに翻訳したリソースを格納、 これらはresources.jsというものでまとめて export することで、アプリ側に読み込んでいくような設定とする。

このやり方の場合、言語の変更を行う場合はソースコード自体を変更するしかないので、実際の運用ではもう少し考える必要がありそうだ。

本来であれば、翻訳した言語は別のSaaS的なもので管理していき、ソースコードを変更せずとも言語ごとのテキストを変えられるようにしたほうが良いと思われる。
例えばi18nextでは locize という多言語管理用のSaaSが親和性が高いようだ。が、結構エンジニアフレンドリーなサービスのようにも感じるので、多言語リソース管理をエンジニアではない人間が担当する場合は、管理を少しばかり考える必要がある。

localization & translation management platform | locize

例えば、先日ブログにも書いたが、contentfulなどのHeadless CMSなどで管理していくのも一つだと思う。

Headless CMS の Contentful からデータを取得して、Next.jsのページで表示させるメモ - at backyard

少し話がそれてしまったが、多言語リソースの管理について書いていく。

先程も書いたが、localesというディレクトリを作成し、下記のように言語を管理していく

src/locales
├── en
 │   └── translation.json
├── ja
 │   └── translation.json
└── resources.js

ここのtranslation.json というファイルには、下記のようにそれぞれの言語でのテキストが入ることになる。

en/translation.json

{
  "Learn React": "Learn React"
}

ja/translation.json

{
  "Learn React": "Reactを学ぶ"
}

これらの言語ファイルをresources.jsでまとめてexportする形だ

import enTranslation from './en/translation';
import jaTranslation from './ja/translation';

export default {
  en: {
    translation: enTranslation
  },
  ja: {
    translation: jaTranslation
  }
};

そして、i18n.jsでは下記のようにresouces.jsを読み込む形に修正する

diff --git a/src/i18n.js b/src/i18n.js
index 5673005..bed5f11 100644
--- a/src/i18n.js
+++ b/src/i18n.js
@@ -1,18 +1,6 @@
 import i18n from 'i18next';
 import { initReactI18next } from 'react-i18next';
-
-const resources = {
-  en: {
-    translation: {
-      'Learn React': 'Learn React'
-    }
-  },
-  ja: {
-    translation: {
-      'Learn React': 'Reactを学ぶ'
-    }
-  }
-};
+import resources from './locales/resources';

 i18n.use(initReactI18next).init({
   resources,

これでひとまずのところ、言語ファイルを分離して管理することができるようになった。
ここについては正直もう少し考えてみる必要がありそうだが、とりあえずの ことはじめ として一旦このような形にした。

Transを用いて、HTMLタグが使われている箇所を多言語化する

下記のようにTranscomponentを用いて多言語化できる。

diff --git a/src/App.js b/src/App.js
index 67b04a9..bbaa97d 100644
--- a/src/App.js
+++ b/src/App.js
@@ -2,19 +2,23 @@ import React from 'react';
 import logo from './logo.svg';
 import './App.css';
 import './i18n';
-import { withTranslation } from 'react-i18next';
+import { withTranslation, Trans } from 'react-i18next';

 function changeLanguage(i18n, lang) {
   i18n.changeLanguage(lang);
 }

 function App({ t, i18n }) {
+  const filename = 'src/App.js';
+
   return (
     <div className="App">
       <header className="App-header">
         <img src={logo} className="App-logo" alt="logo" />
         <p>
-          Edit <code>src/App.js</code> and save to reload.
+          <Trans i18nKey="Save to Reload text">
+            Edit <code>{{ filename }}</code> and save to reload.
+          </Trans>
         </p>
         <a
           className="App-link"

このように記述した場合、テキストファイルには下記のように記述する。

日本語テキスト

{
  "Learn React": "Reactを学ぶ",
  "Save to Reload text": "<1>{{filename}}</1>を編集して保存すると、リロードされます。"
}

英語テキスト

{
  "Learn React": "Reactを学ぶ",
  "Save to Reload text": "<1>{{filename}}</1>を編集して保存すると、リロードされます。"
}

<1> で囲むというところが若干分かりにくい気もするが、、、こういうものなのだろうか?
自分自身あまり使い込めていないので、とりあえず使っていってみる!

この Trans コンポーネントに関する詳細については、下記のページに詳しく書かれている。

Trans Component - react-i18next documentation

addResourceBundleとremoveResourceBundleを用いて、必要て最低限のresourceのみを利用する方法

例えば一度に複数の言語ファイルを読み込みたくないという要望はあると思う。

そういうとき、必要な言語ファイルだけを読み込むにはどうすればよいか?

そこで登場するのが addResourceBundle という関数になる。

また、逆にresourceを削除するための removeResourceBundle という関数もある

https://www.i18next.com/how-to/add-or-load-translations#add-after-init

そこでこれらのコードを利用して、下記のようなコードを作成してみた

まずi18n.jsである。

import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';

i18n.use(initReactI18next).init({
  resources: {},
  fallbackLng: 'en',
  debug: true,

  interpolation: {
    escapeValue: false
  }
});

export default i18n;

ここでは空のresourcesを渡しているが、最初からなんらかの言語情報をresourcesとして渡しても問題ない

ひとまずここでは空のresourcesを渡して、後で動的にリソースを格納していくことにする。

さらに言語resourceの追加・削除、並びに利用する言語の変更を行うための関数を i18-utils.js という名前で作成した。

import resources from './locales/resources';

const resourceKeys = Object.keys(resources);

export const changeLang = (i18n, lang) => {
    // 更新対象のresourceを追加する
    i18n.addResourceBundle(lang, 'translation', resources[lang].translation);

    // 言語変更処理
    i18n.changeLanguage(lang);

    // 不要になったresourceは削除する
    const removeLnaguages = resourceKeys.filter((languag) => languag !== lang);
    for (const removeLang of removeLnaguages) {
        i18n.removeResourceBundle(removeLang, 'translation')
    }

    return;
}

そしてこれらのコードを使った形で下記のようなコードを書く。 ここでは useTranslation を用いたコードで書いていく。

import React, { useCallback, useEffect } from 'react';
import logo from './logo.svg';
import './App.css';
import './i18n';
import { useTranslation, Trans } from 'react-i18next';
import { changeLang } from './i18n-utils';

const App = () => {
  const [ t, i18n ] = useTranslation();

  const filename = 'src/App.js';

  const onClickChangeLanguage = useCallback((lang)  => {
    changeLang(i18n, lang)
  }, [i18n]);

  useEffect(() => {
    changeLang(i18n, 'en')
  }, [])

  console.log(i18n.logger.options.resources)

  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          <Trans i18nKey="Save to Reload text">
            Edit <code>{{ filename }}</code> and save to reload.
          </Trans>
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          {t('Learn')}
        </a>
        <div>
          <p>Change Language</p>
          <button onClick={() => onClickChangeLanguage('en')}>en</button>
          <button onClick={() => onClickChangeLanguage('ja')}>ja</button>
        </div>
        {i18n.languages.map(lang => (
          <p key={lang}>{lang}</p>
        ))}
      </header>
    </div>
  );
}

export default App;

これを実行すると、正常に言語切替が行われる。

また言語切替が行われるタイミングでi18n内に格納されている言語のうち、選択されたもの以外のresourceが削除される。

これは console.log(i18n.logger.options.resources) というデバッグ用の関数を差し込むことで確認が可能。

i18n.languagesの中身について

上のコードでデバッグ目的な下記のような記述を書いた

        {i18n.languages.map(lang => (
          <p key={lang}>{lang}</p>
        ))}

例えば英語を選択した場合、 en が入るが、日本語を選択した場合、ここには en, jaという2つが入る。

なぜ en はこの配列の中に居座り続けているのだろうかと考えたが、ここは

i18n.use(initReactI18next).init({
  resources: {},
  fallbackLng: 'en',
  debug: true,

  interpolation: {
    escapeValue: false
  }
});

ここで fallbackLng として指定していたからだった。

ここで指定すると、i18n.languages の中には居座り続ける仕様となっている、というのは実装する上で頭の中に入れておいたほうが良いかもしれないと思った次第。

react-i18nextでObject(...) is not a functionというエラーに悩まされた

react-i18nextを触る上で、少しハマったことがあったので、最後に書き記しておく。

ここまで書いていたようなことを、とある環境で試していたところ、なぜだか Object(...) is not a function というエラーが出る。
最初、自身のReactの使い方が間違っているのかと疑っていたが、なんてことはなく、react, react-domのバージョンが古いだけだった。。

github.com

私はこの原因を突き止めるのに3時間ほどかけてしまった。猛省した。

B/W、イバラキングのごじゃっぺラジオZに出演してきました!

先日書いていたとおり、B/Wにて、イバラキングのごじゃっぺラジオZに出演してきました!

shinshin86.hateblo.jp

ラジオの公開収録ということで最初は緊張していたものの、始まれば意外と落ち着きながら(?)楽しんで話すことができ、最高に楽しい時間を過ごすことができました。ありがとうございました!

以下、B/Wのツイートを引用

スーパーカーやHomecomings好きなら必聴かも、な台湾のインディギターポップバンド、DSPS

たまたま見つけた下記の記事。

読んで DSPS 聴いてみたら、やはり良かった。
今日のお仕事Musicはこのバンドのアルバムになりそうだ。

DSPS

  • インディー・ロック
music.apple.com

関係ないけど、最近起床時間が早くなってきた。
今年は7時頃に起きるのが習慣だったけど、6時起きに移行してきた。朝早く起きるのはやはり気分が良いもので、グラスにたっぷりと注いだアイスコーヒーを飲みながら、朝焼けの空を眺めていると、なにか曲でも作りたくなってくる。
さて、曲は作らずに仕事の準備だ。PCをリュックに詰め込んで、都内へ向かう。

ブログのタグと、自分をコントローすることの難しさについて

たまには日記っぽいこと書くかと、はてなブログのアプリを開いて、何も考えずに書き出した。

日記っぽいこと書くならタグも '日記' だろうということで日記というタグをつけてみたが、ふと他に日記というタグをつけたポストを書いたかな?と思い、自分のブログを読み返そうとしたが、なんだかそれだけで1時間ぐらい経ってしまいそうな気がしたので、辞めた。

たぶん私だけじゃないだろうが、"あ、そういえばあのバンドの新作聴いてみようかな"と仕事中にApple musicで検索をかけて流すだけのはずが、気づいたら過去のリミックス集とかを色々調べ始めてしまい30分くらい経ってしまう、とかは割とあることだ。

この前だってトムヨークの新作を聴くだけのはずが、過去作やリミックスから、リミキサー陣それぞれのアルバムを検索するに至って、変な疲れを感じたりした。

ちょっとのつもりが思いがけず時間をかけてしまうのはあるあるなので、最近私は自制している。

自制といえば、ここ最近意識的にノンアルコールの日を作るようになった。

別に健康に気を使っているわけではなく、毎日お酒を飲むのが習慣化しているので、その習慣を自ら破ってみようと思い立ったのだ。

ただそんなことを思っていても友人から誘われるとお酒はついつい飲んでしまう。そんな酒の席で、"最近意識的にノンアルコールの日を作ろうとしていてさ〜本当は今日もノンアルコールにするつもりだったのに、飲んじゃった"、なんて話すものだから、私の話は説得力皆無の状態で酒場の隅に追いやられてしまうのだった。

お酒といえば、先日、常陸野ネストビールでお馴染みの木内酒造に足を運んだ。これは近いうちに改めて書こうと思うので、またその時に。 とても楽しかったので、茨城の水戸の方に行く方で、クラフトビール好きの方は是非いってみると良いと思う。友人同士でもカップル同士でも夫婦ででも楽しめるはずだ。グッズも可愛くて、私もグラスとかステッカーとか諸々買ってしまった。おススメ。