Change to split birthday into year, month, and day

This commit is contained in:
noellabo 2023-02-25 15:14:48 +09:00
parent fa82ec15d5
commit 5ebd24c801
13 changed files with 210 additions and 17 deletions

View File

@ -21,7 +21,7 @@ class Api::V1::Accounts::CredentialsController < Api::BaseController
private
def account_params
params.permit(:display_name, :note, :avatar, :header, :locked, :bot, :discoverable, :searchability, :birthday, :location, fields_attributes: [:name, :value])
params.permit(:display_name, :note, :avatar, :header, :locked, :bot, :discoverable, :searchability, :birthday, :birth_year, :birth_month, :birth_day, :location, fields_attributes: [:name, :value])
end
def user_settings_params

View File

@ -20,7 +20,7 @@ class Settings::ProfilesController < Settings::BaseController
private
def account_params
params.require(:account).permit(:display_name, :note, :avatar, :header, :locked, :bot, :discoverable, :searchability, :birthday, :location, fields_attributes: [:name, :value])
params.require(:account).permit(:display_name, :note, :avatar, :header, :locked, :bot, :discoverable, :searchability, :birthday, :birth_year, :birth_month, :birth_day, :location, fields_attributes: [:name, :value])
end
def set_account

View File

@ -58,6 +58,18 @@ const messages = defineMessages({
add_or_remove_from_circle: { id: 'account.add_or_remove_from_circle', defaultMessage: 'Add or Remove from circles' },
admin_account: { id: 'status.admin_account', defaultMessage: 'Open moderation interface for @{name}' },
secret: { id: 'account.secret', defaultMessage: 'Secret' },
birth_month_1: { id: 'account.birthday.month.1', defaultMessage: 'January' },
birth_month_2: { id: 'account.birthday.month.2', defaultMessage: 'February' },
birth_month_3: { id: 'account.birthday.month.3', defaultMessage: 'March' },
birth_month_4: { id: 'account.birthday.month.4', defaultMessage: 'April' },
birth_month_5: { id: 'account.birthday.month.5', defaultMessage: 'May' },
birth_month_6: { id: 'account.birthday.month.6', defaultMessage: 'June' },
birth_month_7: { id: 'account.birthday.month.7', defaultMessage: 'July' },
birth_month_8: { id: 'account.birthday.month.8', defaultMessage: 'August' },
birth_month_9: { id: 'account.birthday.month.9', defaultMessage: 'September' },
birth_month_10: { id: 'account.birthday.month.10', defaultMessage: 'October' },
birth_month_11: { id: 'account.birthday.month.11', defaultMessage: 'November' },
birth_month_12: { id: 'account.birthday.month.12', defaultMessage: 'December' },
});
const dateFormatOptions = {
@ -354,9 +366,38 @@ class Header extends ImmutablePureComponent {
const hide_followers_count = account.getIn(['other_settings', 'hide_followers_count'], false);
const location = account.getIn(['other_settings', 'location']);
const birthday = account.getIn(['other_settings', 'birthday']);
const joined = account.get('created_at');
const birthday = (() => {
const birth_year = account.getIn(['other_settings', 'birth_year'], null);
const birth_month = account.getIn(['other_settings', 'birth_month'], null);
const birth_day = account.getIn(['other_settings', 'birth_day'], null);
const birth_month_name = birth_month >= 1 && birth_month <= 12 ? intl.formatMessage(messages[`birth_month_${birth_month}`]) : null;
if (birth_year && birth_month && birth_day) {
const date = new Date(birth_year, birth_month - 1, birth_day);
return <Fragment><FormattedDate value={date} hour12={false} year='numeric' month='short' day='2-digit' />(<FormattedMessage id='account.age' defaultMessage='{age} years old}' values={{ age: age(date) }} />)</Fragment>;
} else if (birth_month && birth_day) {
return <FormattedMessage id='account.birthday.month_day' defaultMessage='{month_name} {day}' values={{ month: birth_month, day: birth_day, month_name: birth_month_name }} />;
} else if (birth_year && birth_month) {
return <FormattedMessage id='account.birthday.year_month' defaultMessage='{month_name}, {year}' values={{ year: birth_year, month: birth_month, month_name: birth_month_name }} />;
} else if (birth_year) {
return <FormattedMessage id='account.birthday.year' defaultMessage='{year}' values={{ year: birth_year }} />;
} else if (birth_month) {
return <FormattedMessage id='account.birthday.month' defaultMessage='{month_name}' values={{ month: birth_month, day: birth_day, month_name: birth_month_name }} />;
} else if (birth_day) {
return null;
} else {
const date = account.getIn(['other_settings', 'birthday'], null);
if (date) {
return <Fragment><FormattedDate value={date} hour12={false} year='numeric' month='short' day='2-digit' />(<FormattedMessage id='account.age' defaultMessage='{age} years old}' values={{ age: age(date) }} />)</Fragment>;
} else {
return null;
}
}
})();
return (
<div className={classNames('account__header', { inactive: !!account.get('moved') })} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave}>
<div className='account__header__image'>
@ -437,7 +478,7 @@ class Header extends ImmutablePureComponent {
</tr>}
{birthday && <tr>
<th><Icon id='birthday-cake' fixedWidth aria-hidden='true' /> <FormattedMessage id='account.birthday' defaultMessage='Birthday' /></th>
<td><FormattedDate value={birthday} hour12={false} year='numeric' month='short' day='2-digit' />(<FormattedMessage id='account.age' defaultMessage='{age} years old}' values={{age: age(birthday)}} />)</td>
<td>{birthday}</td>
</tr>}
<tr>
<th><Icon id='calendar' fixedWidth aria-hidden='true' /> <FormattedMessage id='account.joined' defaultMessage='Joined' /></th>

View File

@ -1,4 +1,4 @@
import React from 'react';
import React, { Fragment } from 'react';
import ImmutablePropTypes from 'react-immutable-proptypes';
import PropTypes from 'prop-types';
import { defineMessages, injectIntl, FormattedMessage, FormattedDate } from 'react-intl';
@ -11,6 +11,18 @@ import classNames from 'classnames';
const messages = defineMessages({
linkVerifiedOn: { id: 'account.link_verified_on', defaultMessage: 'Ownership of this link was checked on {date}' },
birth_month_1: { id: 'account.birthday.month.1', defaultMessage: 'January' },
birth_month_2: { id: 'account.birthday.month.2', defaultMessage: 'February' },
birth_month_3: { id: 'account.birthday.month.3', defaultMessage: 'March' },
birth_month_4: { id: 'account.birthday.month.4', defaultMessage: 'April' },
birth_month_5: { id: 'account.birthday.month.5', defaultMessage: 'May' },
birth_month_6: { id: 'account.birthday.month.6', defaultMessage: 'June' },
birth_month_7: { id: 'account.birthday.month.7', defaultMessage: 'July' },
birth_month_8: { id: 'account.birthday.month.8', defaultMessage: 'August' },
birth_month_9: { id: 'account.birthday.month.9', defaultMessage: 'September' },
birth_month_10: { id: 'account.birthday.month.10', defaultMessage: 'October' },
birth_month_11: { id: 'account.birthday.month.11', defaultMessage: 'November' },
birth_month_12: { id: 'account.birthday.month.12', defaultMessage: 'December' },
});
const dateFormatOptions = {
@ -52,9 +64,38 @@ class HeaderExtra extends ImmutablePureComponent {
const fields = account.get('fields');
const location = account.getIn(['other_settings', 'location']);
const birthday = account.getIn(['other_settings', 'birthday']);
const joined = account.get('created_at');
const birthday = (() => {
const birth_year = account.getIn(['other_settings', 'birth_year'], null);
const birth_month = account.getIn(['other_settings', 'birth_month'], null);
const birth_day = account.getIn(['other_settings', 'birth_day'], null);
const birth_month_name = birth_month >= 1 && birth_month <= 12 ? intl.formatMessage(messages[`birth_month_${birth_month}`]) : null;
if (birth_year && birth_month && birth_day) {
const date = new Date(birth_year, birth_month - 1, birth_day);
return <Fragment><FormattedDate value={date} hour12={false} year='numeric' month='short' day='2-digit' />(<FormattedMessage id='account.age' defaultMessage='{age} years old}' values={{ age: age(date) }} />)</Fragment>;
} else if (birth_month && birth_day) {
return <FormattedMessage id='account.birthday.month_day' defaultMessage='{month_name} {day}' values={{ month: birth_month, day: birth_day, month_name: birth_month_name }} />;
} else if (birth_year && birth_month) {
return <FormattedMessage id='account.birthday.year_month' defaultMessage='{month_name}, {year}' values={{ year: birth_year, month: birth_month, month_name: birth_month_name }} />;
} else if (birth_year) {
return <FormattedMessage id='account.birthday.year' defaultMessage='{year}' values={{ year: birth_year }} />;
} else if (birth_month) {
return <FormattedMessage id='account.birthday.month' defaultMessage='{month_name}' values={{ month: birth_month, day: birth_day, month_name: birth_month_name }} />;
} else if (birth_day) {
return null;
} else {
const date = account.getIn(['other_settings', 'birthday'], null);
if (date) {
return <Fragment><FormattedDate value={date} hour12={false} year='numeric' month='short' day='2-digit' />(<FormattedMessage id='account.age' defaultMessage='{age} years old}' values={{ age: age(date) }} />)</Fragment>;
} else {
return null;
}
}
})();
return (
<div className={classNames('account__header', 'advanced', { inactive: !!account.get('moved') })}>
<div className='account__header__extra'>
@ -98,7 +139,7 @@ class HeaderExtra extends ImmutablePureComponent {
</tr>}
{birthday && <tr>
<th><Icon id='birthday-cake' fixedWidth aria-hidden='true' /> <FormattedMessage id='account.birthday' defaultMessage='Birthday' /></th>
<td><FormattedDate value={birthday} hour12={false} year='numeric' month='short' day='2-digit' />(<FormattedMessage id='account.age' defaultMessage='{age} years old}' values={{ age: age(birthday) }} />)</td>
<td>{birthday}</td>
</tr>}
<tr>
<th><Icon id='calendar' fixedWidth aria-hidden='true' /> <FormattedMessage id='account.joined' defaultMessage='Joined' /></th>

View File

@ -6,6 +6,22 @@
"account.badges.bot": "Bot",
"account.badges.group": "Group",
"account.birthday": "Birthday",
"account.birthday.month": "{month_name}",
"account.birthday.month.1": "January",
"account.birthday.month.2": "February",
"account.birthday.month.3": "March",
"account.birthday.month.4": "April",
"account.birthday.month.5": "May",
"account.birthday.month.6": "June",
"account.birthday.month.7": "July",
"account.birthday.month.8": "August",
"account.birthday.month.9": "September",
"account.birthday.month.10": "October",
"account.birthday.month.11": "November",
"account.birthday.month.12": "December",
"account.birthday.month_day": "{month_name} {day}",
"account.birthday.year": "{year}",
"account.birthday.year_month": "{month_name}, {year}",
"account.block": "Block @{name}",
"account.block_domain": "Block domain {domain}",
"account.blocked": "Blocked",

View File

@ -6,6 +6,22 @@
"account.badges.bot": "Bot",
"account.badges.group": "Group",
"account.birthday": "誕生日",
"account.birthday.month": "{month}月",
"account.birthday.month.1": "睦月",
"account.birthday.month.2": "如月",
"account.birthday.month.3": "弥生",
"account.birthday.month.4": "卯月",
"account.birthday.month.5": "皐月",
"account.birthday.month.6": "水無月",
"account.birthday.month.7": "文月",
"account.birthday.month.8": "葉月",
"account.birthday.month.9": "長月",
"account.birthday.month.10": "神無月",
"account.birthday.month.11": "霜月",
"account.birthday.month.12": "師走",
"account.birthday.month_day": "{month}月{day}日",
"account.birthday.year": "{year}年",
"account.birthday.year_month": "{year}年{month}月",
"account.block": "@{name}さんをブロック",
"account.block_domain": "{domain}全体をブロック",
"account.blocked": "ブロック済み",

View File

@ -293,6 +293,14 @@ code {
flex: 1 1 auto;
min-height: 1px;
&-2 {
max-width: 16.7%;
}
&-4 {
max-width: 33.3%;
}
&-6 {
max-width: 50%;
}
@ -301,6 +309,10 @@ code {
max-width: 66.67%;
}
&-12 {
max-width: 100%;
}
.actions {
margin-top: 27px;
}

View File

@ -26,7 +26,49 @@ module AccountSettings
end
def birthday=(val)
settings['birthday'] = ActiveRecord::Type::Date.new.cast(val)
set_birthday(val)
end
def birth_year
settings['birth_year'] || birthday && ActiveRecord::Type::Date.new.cast(birthday).year
end
def birth_year=(val)
settings['birth_year'] = Integer(val).then { |val| (0..9999).cover?(val) ? val : nil } rescue nil
normalize_birthday
end
def birth_month
settings['birth_month'] || birthday && ActiveRecord::Type::Date.new.cast(birthday).month
end
def birth_month=(val)
settings['birth_month'] = Integer(val).then { |val| (1..12).cover?(val) ? val : nil } rescue nil
normalize_birthday
end
def birth_day
settings['birth_day'] || birthday && ActiveRecord::Type::Date.new.cast(birthday).day
end
def birth_day=(val)
settings['birth_day'] = Integer(val).then { |val| (1..31).cover?(val) ? val : nil } rescue nil
normalize_birthday
end
def normalize_birthday
date = Date.new(settings['birth_year'], settings['birth_month'], settings['birth_day']) rescue nil
set_birthday(date)
end
def set_birthday(val)
date = ActiveRecord::Type::Date.new.cast(val)
if date.class.name === 'Date'
settings['birthday'] = date
else
settings.delete('birthday')
end
end
def location

View File

@ -27,7 +27,7 @@ class ActivityPub::ActorSerializer < ActivityPub::Serializer
attribute :moved_to, if: :moved?
attribute :also_known_as, if: :also_known_as?
attribute :suspended, if: :suspended?
attribute :bday, key: :'vcard:bday'
attribute :bday, key: :'vcard:bday', if: :bday?
attribute :address, key: :'vcard:Address'
has_many :virtual_other_settings, key: :other_setting
@ -177,6 +177,10 @@ class ActivityPub::ActorSerializer < ActivityPub::Serializer
object.birthday
end
def bday?
object.birthday
end
def address
object.location
end

View File

@ -260,6 +260,9 @@ class ActivityPub::ProcessAccountService < BaseService
DEFER_SETTINGS_KEYS = %w(
birthday
birth_year
birth_month
birth_day
location
cat_ears_color
noindex

View File

@ -60,8 +60,14 @@
%p.warning-hint= t('simple_form.hints.defaults.searchability')
.fields-row
.fields-row__column.fields-group.fields-row__column-8
= f.input :birthday, wrapper: :with_label, input_html: { placeholder: '2016-03-16', pattern: '\d{4}-\d{1,2}-\d{1,2}' }, hint: t('simple_form.hints.defaults.birthday'), fedibird_features: true
.fields-row__column.fields-group.fields-row__column-2
= f.input :birth_year, wrapper: :with_label, input_html: { pattern: '\d{1,4}' }, hint: t('simple_form.hints.defaults.birth_year'), fedibird_features: true
.fields-row__column.fields-group.fields-row__column-2
= f.input :birth_month, wrapper: :with_label, input_html: { pattern: '\d{1,2}' }, hint: t('simple_form.hints.defaults.birth_month'), fedibird_features: true
.fields-row__column.fields-group.fields-row__column-2
= f.input :birth_day, wrapper: :with_label, input_html: { pattern: '\d{1,2}' }, hint: t('simple_form.hints.defaults.birth_day'), fedibird_features: true
.fields-row__column.fields-group.fields-row__column-6
%p.hint= t('simple_form.hints.defaults.birth_description')
%p.warning-hint= t('simple_form.hints.defaults.birthday_caution')
.fields-row

View File

@ -33,8 +33,11 @@ en:
defaults:
autofollow: People who sign up through the invite will automatically follow you
avatar: PNG, GIF or JPG. At most %{size}. Will be downscaled to %{dimensions}px
birthday: Specify the date of birth in the format yyyy-mm-ddex. 2016-03-16
birthday_caution: It will be published on the Internet. Please handle your personal information with care
birthday_caution: It will be published on the Internet. Please handle your personal information with care.
birth_day: 1-31
birth_month: 1-12
birth_year: 0-9999
birth_description: Specify the date of birth. If you enter a full date, it is compatible with Misskey.
bot: Signal to others that the account mainly performs automated actions and might not be monitored
context: One or multiple contexts where the filter should apply
current_password: For security purposes please enter the password of the current account
@ -48,7 +51,7 @@ en:
irreversible: Filtered posts will disappear irreversibly, even if filter is later removed
locale: The language of the user interface, e-mails and push notifications
location: Area of primary residence or activity
location_caution: It will be published on the Internet. Please do not include detailed addresses except for business use
location_caution: It will be published on the Internet. Please do not include detailed addresses except for business use.
locked: Manually control who can follow you by approving follow requests
password: Use at least 8 characters
phrase: Will be matched regardless of casing in text or content warning of a post
@ -218,6 +221,9 @@ en:
autofollow: Invite to follow your account
avatar: Avatar
birthday: Birthday
birth_day: Birth day
birth_month: Birth month
birth_year: Birth year
bot: This is a bot account
chosen_languages: Filter languages
confirm_new_password: Confirm new password

View File

@ -33,8 +33,11 @@ ja:
defaults:
autofollow: 招待から登録した人が自動的にあなたをフォローするようになります
avatar: "%{size}までのPNG、GIF、JPGが利用可能です。%{dimensions}pxまで縮小されます"
birthday: 誕生日を年月日の順にyyyy-mm-ddex. 2016-03-16という書式で指定します
birthday_caution: インターネットに公開されます。個人情報は慎重に取り扱ってください
birthday_caution: インターネットに公開されます。個人情報は慎重に取り扱ってください。
birth_day: 1〜31
birth_month: 1〜12
birth_year: 0〜9999
birth_description: 誕生日を指定します。完全な日付を入力した場合はMisskeyと互換性があります。
bot: このアカウントは主に自動で動作し、人が見ていない可能性があります
context: フィルターを適用する対象 (複数選択可)
current_password: 現在のアカウントのパスワードを入力してください
@ -48,7 +51,7 @@ ja:
irreversible: フィルターが後で削除されても、除外された投稿は元に戻せなくなります
locale: ユーザーインターフェース、メールやプッシュ通知の言語
location: 主に居住・活動する地域・場所
location_caution: インターネットに公開されます。ビジネス用途を除き詳細な住所を記載しないでください
location_caution: インターネットに公開されます。ビジネス用途を除き詳細な住所を記載しないでください
locked: フォロワーを手動で承認する必要があります
password: 少なくとも8文字は入力してください
phrase: 投稿内容の大文字小文字や閲覧注意に関係なく一致
@ -214,6 +217,9 @@ ja:
autofollow: 招待から参加後、あなたをフォロー
avatar: アイコン
birthday: 誕生日
birth_day: 誕生日
birth_month: 誕生月
birth_year: 誕生年
bot: これは BOT アカウントです
chosen_languages: 表示する言語
confirm_new_password: 新しいパスワード(確認用)