Merge remote-tracking branch 'parent/main' into upstream-20240229
This commit is contained in:
commit
4b5fc77b6e
59 changed files with 562 additions and 780 deletions
|
@ -80,7 +80,7 @@ export default class MediaContainer extends PureComponent {
|
|||
return (
|
||||
<IntlProvider>
|
||||
<>
|
||||
{[].map.call(components, (component, i) => {
|
||||
{Array.from(components).map((component, i) => {
|
||||
const componentName = component.getAttribute('data-component');
|
||||
const Component = MEDIA_COMPONENTS[componentName];
|
||||
const { media, card, poll, hashtag, ...props } = JSON.parse(component.getAttribute('data-props'));
|
||||
|
|
|
@ -141,6 +141,7 @@ class LanguageDropdownMenu extends PureComponent {
|
|||
case 'Escape':
|
||||
onClose();
|
||||
break;
|
||||
case ' ':
|
||||
case 'Enter':
|
||||
this.handleClick(e);
|
||||
break;
|
||||
|
|
|
@ -5,14 +5,12 @@ import { injectIntl, defineMessages } from 'react-intl';
|
|||
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { supportsPassiveEvents } from 'detect-passive-events';
|
||||
import Overlay from 'react-overlays/Overlay';
|
||||
|
||||
import CircleIcon from '@/material-icons/400-24px/account_circle.svg?react';
|
||||
import AlternateEmailIcon from '@/material-icons/400-24px/alternate_email.svg?react';
|
||||
import PublicUnlistedIcon from '@/material-icons/400-24px/cloud.svg?react';
|
||||
import MutualIcon from '@/material-icons/400-24px/compare_arrows.svg?react';
|
||||
import InfoIcon from '@/material-icons/400-24px/info.svg?react';
|
||||
import LoginIcon from '@/material-icons/400-24px/key.svg?react';
|
||||
import LockIcon from '@/material-icons/400-24px/lock.svg?react';
|
||||
import PublicIcon from '@/material-icons/400-24px/public.svg?react';
|
||||
|
@ -22,6 +20,8 @@ import LimitedIcon from '@/material-icons/400-24px/shield.svg?react';
|
|||
import { Icon } from 'mastodon/components/icon';
|
||||
import { enableLoginPrivacy, enableLocalPrivacy, enablePublicPrivacy } from 'mastodon/initial_state';
|
||||
|
||||
import { PrivacyDropdownMenu } from './privacy_dropdown_menu';
|
||||
|
||||
const messages = defineMessages({
|
||||
public_short: { id: 'privacy.public.short', defaultMessage: 'Public' },
|
||||
public_long: { id: 'privacy.public.long', defaultMessage: 'Anyone on and off Mastodon' },
|
||||
|
@ -46,126 +46,6 @@ const messages = defineMessages({
|
|||
unlisted_extra: { id: 'privacy.unlisted.additional', defaultMessage: 'This behaves exactly like public, except the post will not appear in live feeds or hashtags, explore, or Mastodon search, even if you are opted-in account-wide.' },
|
||||
});
|
||||
|
||||
const listenerOptions = supportsPassiveEvents ? { passive: true, capture: true } : true;
|
||||
|
||||
class PrivacyDropdownMenu extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
style: PropTypes.object,
|
||||
items: PropTypes.array.isRequired,
|
||||
value: PropTypes.string.isRequired,
|
||||
onClose: PropTypes.func.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
handleDocumentClick = e => {
|
||||
if (this.node && !this.node.contains(e.target)) {
|
||||
this.props.onClose();
|
||||
e.stopPropagation();
|
||||
}
|
||||
};
|
||||
|
||||
handleKeyDown = e => {
|
||||
const { items } = this.props;
|
||||
const value = e.currentTarget.getAttribute('data-index');
|
||||
const index = items.findIndex(item => {
|
||||
return (item.value === value);
|
||||
});
|
||||
let element = null;
|
||||
|
||||
switch(e.key) {
|
||||
case 'Escape':
|
||||
this.props.onClose();
|
||||
break;
|
||||
case 'Enter':
|
||||
this.handleClick(e);
|
||||
break;
|
||||
case 'ArrowDown':
|
||||
element = this.node.childNodes[index + 1] || this.node.firstChild;
|
||||
break;
|
||||
case 'ArrowUp':
|
||||
element = this.node.childNodes[index - 1] || this.node.lastChild;
|
||||
break;
|
||||
case 'Tab':
|
||||
if (e.shiftKey) {
|
||||
element = this.node.childNodes[index - 1] || this.node.lastChild;
|
||||
} else {
|
||||
element = this.node.childNodes[index + 1] || this.node.firstChild;
|
||||
}
|
||||
break;
|
||||
case 'Home':
|
||||
element = this.node.firstChild;
|
||||
break;
|
||||
case 'End':
|
||||
element = this.node.lastChild;
|
||||
break;
|
||||
}
|
||||
|
||||
if (element) {
|
||||
element.focus();
|
||||
this.props.onChange(element.getAttribute('data-index'));
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
};
|
||||
|
||||
handleClick = e => {
|
||||
const value = e.currentTarget.getAttribute('data-index');
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
this.props.onClose();
|
||||
this.props.onChange(value);
|
||||
};
|
||||
|
||||
componentDidMount () {
|
||||
document.addEventListener('click', this.handleDocumentClick, { capture: true });
|
||||
document.addEventListener('touchend', this.handleDocumentClick, listenerOptions);
|
||||
if (this.focusedItem) this.focusedItem.focus({ preventScroll: true });
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
document.removeEventListener('click', this.handleDocumentClick, { capture: true });
|
||||
document.removeEventListener('touchend', this.handleDocumentClick, listenerOptions);
|
||||
}
|
||||
|
||||
setRef = c => {
|
||||
this.node = c;
|
||||
};
|
||||
|
||||
setFocusRef = c => {
|
||||
this.focusedItem = c;
|
||||
};
|
||||
|
||||
render () {
|
||||
const { style, items, value } = this.props;
|
||||
|
||||
return (
|
||||
<div style={{ ...style }} role='listbox' ref={this.setRef}>
|
||||
{items.map(item => (
|
||||
<div role='option' tabIndex={0} key={item.value} data-index={item.value} onKeyDown={this.handleKeyDown} onClick={this.handleClick} className={classNames('privacy-dropdown__option', { active: item.value === value })} aria-selected={item.value === value} ref={item.value === value ? this.setFocusRef : null}>
|
||||
<div className='privacy-dropdown__option__icon'>
|
||||
<Icon id={item.icon} icon={item.iconComponent} />
|
||||
</div>
|
||||
|
||||
<div className='privacy-dropdown__option__content'>
|
||||
<strong>{item.text}</strong>
|
||||
{item.meta}
|
||||
</div>
|
||||
|
||||
{item.extra && (
|
||||
<div className='privacy-dropdown__option__additional' title={item.extra}>
|
||||
<Icon id='info-circle' icon={item.extraIcomComponent ?? InfoIcon} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class PrivacyDropdown extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
|
|
|
@ -0,0 +1,128 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { supportsPassiveEvents } from 'detect-passive-events';
|
||||
|
||||
import InfoIcon from '@/material-icons/400-24px/info.svg?react';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
|
||||
const listenerOptions = supportsPassiveEvents ? { passive: true, capture: true } : true;
|
||||
|
||||
export const PrivacyDropdownMenu = ({ style, items, value, onClose, onChange }) => {
|
||||
const nodeRef = useRef(null);
|
||||
const focusedItemRef = useRef(null);
|
||||
const [currentValue, setCurrentValue] = useState(value);
|
||||
|
||||
const handleDocumentClick = useCallback((e) => {
|
||||
if (nodeRef.current && !nodeRef.current.contains(e.target)) {
|
||||
onClose();
|
||||
e.stopPropagation();
|
||||
}
|
||||
}, [nodeRef, onClose]);
|
||||
|
||||
const handleClick = useCallback((e) => {
|
||||
const value = e.currentTarget.getAttribute('data-index');
|
||||
|
||||
e.preventDefault();
|
||||
|
||||
onClose();
|
||||
onChange(value);
|
||||
}, [onClose, onChange]);
|
||||
|
||||
const handleKeyDown = useCallback((e) => {
|
||||
const value = e.currentTarget.getAttribute('data-index');
|
||||
const index = items.findIndex(item => (item.value === value));
|
||||
|
||||
let element = null;
|
||||
|
||||
switch (e.key) {
|
||||
case 'Escape':
|
||||
onClose();
|
||||
break;
|
||||
case ' ':
|
||||
case 'Enter':
|
||||
handleClick(e);
|
||||
break;
|
||||
case 'ArrowDown':
|
||||
element = nodeRef.current.childNodes[index + 1] || nodeRef.current.firstChild;
|
||||
break;
|
||||
case 'ArrowUp':
|
||||
element = nodeRef.current.childNodes[index - 1] || nodeRef.current.lastChild;
|
||||
break;
|
||||
case 'Tab':
|
||||
if (e.shiftKey) {
|
||||
element = nodeRef.current.childNodes[index + 1] || nodeRef.current.firstChild;
|
||||
} else {
|
||||
element = nodeRef.current.childNodes[index - 1] || nodeRef.current.lastChild;
|
||||
}
|
||||
break;
|
||||
case 'Home':
|
||||
element = nodeRef.current.firstChild;
|
||||
break;
|
||||
case 'End':
|
||||
element = nodeRef.current.lastChild;
|
||||
break;
|
||||
}
|
||||
|
||||
if (element) {
|
||||
element.focus();
|
||||
setCurrentValue(element.getAttribute('data-index'));
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
}, [nodeRef, items, onClose, handleClick, setCurrentValue]);
|
||||
|
||||
useEffect(() => {
|
||||
document.addEventListener('click', handleDocumentClick, { capture: true });
|
||||
document.addEventListener('touchend', handleDocumentClick, listenerOptions);
|
||||
focusedItemRef.current?.focus({ preventScroll: true });
|
||||
|
||||
return () => {
|
||||
document.removeEventListener('click', handleDocumentClick, { capture: true });
|
||||
document.removeEventListener('touchend', handleDocumentClick, listenerOptions);
|
||||
};
|
||||
}, [handleDocumentClick]);
|
||||
|
||||
return (
|
||||
<ul style={{ ...style }} role='listbox' ref={nodeRef}>
|
||||
{items.map(item => (
|
||||
<li
|
||||
role='option'
|
||||
tabIndex={0}
|
||||
key={item.value}
|
||||
data-index={item.value}
|
||||
onKeyDown={handleKeyDown}
|
||||
onClick={handleClick}
|
||||
className={classNames('privacy-dropdown__option', { active: item.value === currentValue })}
|
||||
aria-selected={item.value === currentValue}
|
||||
ref={item.value === currentValue ? focusedItemRef : null}
|
||||
>
|
||||
<div className='privacy-dropdown__option__icon'>
|
||||
<Icon id={item.icon} icon={item.iconComponent} />
|
||||
</div>
|
||||
|
||||
<div className='privacy-dropdown__option__content'>
|
||||
<strong>{item.text}</strong>
|
||||
{item.meta}
|
||||
</div>
|
||||
|
||||
{item.extra && (
|
||||
<div className='privacy-dropdown__option__additional' title={item.extra}>
|
||||
<Icon id='info-circle' icon={item.extraIcomComponent ?? InfoIcon} />
|
||||
</div>
|
||||
)}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
);
|
||||
};
|
||||
|
||||
PrivacyDropdownMenu.propTypes = {
|
||||
style: PropTypes.object,
|
||||
items: PropTypes.array.isRequired,
|
||||
value: PropTypes.string.isRequired,
|
||||
onClose: PropTypes.func.isRequired,
|
||||
onChange: PropTypes.func.isRequired,
|
||||
};
|
|
@ -36,7 +36,7 @@ Object.keys(emojiIndex.emojis).forEach(key => {
|
|||
let emoji = emojiIndex.emojis[key];
|
||||
|
||||
// Emojis with skin tone modifiers are stored like this
|
||||
if (Object.prototype.hasOwnProperty.call(emoji, '1')) {
|
||||
if (Object.hasOwn(emoji, '1')) {
|
||||
emoji = emoji['1'];
|
||||
}
|
||||
|
||||
|
@ -88,7 +88,7 @@ Object.keys(emojiIndex.emojis).forEach(key => {
|
|||
let emoji = emojiIndex.emojis[key];
|
||||
|
||||
// Emojis with skin tone modifiers are stored like this
|
||||
if (Object.prototype.hasOwnProperty.call(emoji, '1')) {
|
||||
if (Object.hasOwn(emoji, '1')) {
|
||||
emoji = emoji['1'];
|
||||
}
|
||||
|
||||
|
|
|
@ -135,19 +135,19 @@ function getData(emoji, skin, set) {
|
|||
}
|
||||
}
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(data.short_names, emoji)) {
|
||||
if (Object.hasOwn(data.short_names, emoji)) {
|
||||
emoji = data.short_names[emoji];
|
||||
}
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(data.emojis, emoji)) {
|
||||
if (Object.hasOwn(data.emojis, emoji)) {
|
||||
emojiData = data.emojis[emoji];
|
||||
}
|
||||
} else if (emoji.id) {
|
||||
if (Object.prototype.hasOwnProperty.call(data.short_names, emoji.id)) {
|
||||
if (Object.hasOwn(data.short_names, emoji.id)) {
|
||||
emoji.id = data.short_names[emoji.id];
|
||||
}
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(data.emojis, emoji.id)) {
|
||||
if (Object.hasOwn(data.emojis, emoji.id)) {
|
||||
emojiData = data.emojis[emoji.id];
|
||||
skin = skin || emoji.skin;
|
||||
}
|
||||
|
@ -216,7 +216,7 @@ function deepMerge(a, b) {
|
|||
let originalValue = a[key],
|
||||
value = originalValue;
|
||||
|
||||
if (Object.prototype.hasOwnProperty.call(b, key)) {
|
||||
if (Object.hasOwn(b, key)) {
|
||||
value = b[key];
|
||||
}
|
||||
|
||||
|
|
|
@ -500,7 +500,7 @@
|
|||
"onboarding.share.message": "{username} naiz #Mastodon-en! Jarrai nazazu hemen: {url}",
|
||||
"onboarding.share.next_steps": "Hurrengo urrats posibleak:",
|
||||
"onboarding.share.title": "Partekatu zure profila",
|
||||
"onboarding.start.lead": "Zure Mastodoneko kontu berria prest dago. Jakin nola atera diezaioekun etekin handiena hemen:",
|
||||
"onboarding.start.lead": "Mastodonen parte zara orain, bakarra eta deszentralizatua den sare-sozialaren plataforma, non zuk, eta ez algoritmo batek, zeure esperientzia pertsonaliza dezakezun. Igaro ezazu muga soziala:",
|
||||
"onboarding.start.skip": "Urrats guztiak saltatu nahi dituzu?",
|
||||
"onboarding.start.title": "Lortu duzu!",
|
||||
"onboarding.steps.follow_people.body": "Zure jarioa zuk pertsonalizatzen duzu. Bete dezagun jende interesgarriaz.",
|
||||
|
|
|
@ -110,7 +110,7 @@
|
|||
"column.about": "درباره",
|
||||
"column.blocks": "کاربران مسدود شده",
|
||||
"column.bookmarks": "نشانکها",
|
||||
"column.community": "خط زمانی محلّی",
|
||||
"column.community": "خط زمانی محلی",
|
||||
"column.direct": "اشارههای خصوصی",
|
||||
"column.directory": "مرور نمایهها",
|
||||
"column.domain_blocks": "دامنههای مسدود شده",
|
||||
|
@ -131,7 +131,7 @@
|
|||
"column_header.show_settings": "نمایش تنظیمات",
|
||||
"column_header.unpin": "برداشتن سنجاق",
|
||||
"column_subheading.settings": "تنظیمات",
|
||||
"community.column_settings.local_only": "فقط محلّی",
|
||||
"community.column_settings.local_only": "فقط محلی",
|
||||
"community.column_settings.media_only": "فقط رسانه",
|
||||
"community.column_settings.remote_only": "تنها دوردست",
|
||||
"compose.language.change": "تغییر زبان",
|
||||
|
@ -228,7 +228,7 @@
|
|||
"empty_column.account_unavailable": "نمایهٔ موجود نیست",
|
||||
"empty_column.blocks": "هنوز کسی را مسدود نکردهاید.",
|
||||
"empty_column.bookmarked_statuses": "هنوز هیچ فرستهٔ نشانهگذاری شدهای ندارید. هنگامی که فرستهای را نشانهگذاری کنید، اینجا نشان داده خواهد شد.",
|
||||
"empty_column.community": "خط زمانی محلّی خالی است. چیزی بنویسید تا چرخش بچرخد!",
|
||||
"empty_column.community": "خط زمانی محلی خالیست. چیزی نوشته تا چرخش بچرخد!",
|
||||
"empty_column.direct": "هنوز هیچ اشاره خصوصیای ندارید. هنگامی که چنین پیامی بگیرید یا بفرستید اینجا نشان داده خواهد شد.",
|
||||
"empty_column.domain_blocks": "هنوز هیچ دامنهای مسدود نشده است.",
|
||||
"empty_column.explore_statuses": "الآن چیزی پرطرفدار نیست. بعداً دوباره بررسی کنید!",
|
||||
|
@ -277,6 +277,17 @@
|
|||
"follow_request.authorize": "اجازه دهید",
|
||||
"follow_request.reject": "رد کنید",
|
||||
"follow_requests.unlocked_explanation": "با این که حسابتان قفل نیست، کارکنان {domain} فکر کردند که ممکن است بخواهید درخواستها از این حسابها را به صورت دستی بازبینی کنید.",
|
||||
"follow_suggestions.curated_suggestion": "گزینش سردبیر",
|
||||
"follow_suggestions.dismiss": "دیگر نشان داده نشود",
|
||||
"follow_suggestions.hints.featured": "این نمایه به دست گروه {domain} دستچین شده.",
|
||||
"follow_suggestions.hints.friends_of_friends": "این نمایه بین کسانی که پی میگیرید محبوب است.",
|
||||
"follow_suggestions.hints.most_followed": "این نمایه روی {domain} بسیار پیگرفته شده.",
|
||||
"follow_suggestions.hints.most_interactions": "این نمایه اخیراُ روی {domain} توجّه زیادی گرفته.",
|
||||
"follow_suggestions.hints.similar_to_recently_followed": "این نمایه شبیه نمایههاییست که اخیراً پیگرفتهاید.",
|
||||
"follow_suggestions.personalized_suggestion": "پیشنهاد شخصی",
|
||||
"follow_suggestions.popular_suggestion": "پیشنهاد محبوب",
|
||||
"follow_suggestions.view_all": "دیدن همه",
|
||||
"follow_suggestions.who_to_follow": "افرادی برای پیگیری",
|
||||
"followed_tags": "برچسبهای پیگرفته",
|
||||
"footer.about": "درباره",
|
||||
"footer.directory": "فهرست نمایهها",
|
||||
|
@ -345,7 +356,7 @@
|
|||
"keyboard_shortcuts.home": "گشودن خط زمانی خانگی",
|
||||
"keyboard_shortcuts.hotkey": "میانبر",
|
||||
"keyboard_shortcuts.legend": "نمایش این نشانه",
|
||||
"keyboard_shortcuts.local": "گشودن خط زمانی محلّی",
|
||||
"keyboard_shortcuts.local": "گشودن خط زمانی محلی",
|
||||
"keyboard_shortcuts.mention": "اشاره به نویسنده",
|
||||
"keyboard_shortcuts.muted": "گشودن فهرست کاربران خموش",
|
||||
"keyboard_shortcuts.my_profile": "گشودن نمایهتان",
|
||||
|
@ -396,7 +407,7 @@
|
|||
"navigation_bar.advanced_interface": "بازکردن در رابط کاربری وب پیشرفته",
|
||||
"navigation_bar.blocks": "کاربران مسدود شده",
|
||||
"navigation_bar.bookmarks": "نشانکها",
|
||||
"navigation_bar.community_timeline": "خط زمانی محلّی",
|
||||
"navigation_bar.community_timeline": "خط زمانی محلی",
|
||||
"navigation_bar.compose": "نوشتن فرستهٔ تازه",
|
||||
"navigation_bar.direct": "اشارههای خصوصی",
|
||||
"navigation_bar.discover": "گشت و گذار",
|
||||
|
@ -475,8 +486,10 @@
|
|||
"onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!",
|
||||
"onboarding.follows.title": "Popular on Mastodon",
|
||||
"onboarding.profile.discoverable": "نمایه خود را قابل نمایش کنید",
|
||||
"onboarding.profile.discoverable_hint": "خواستهاید روی ماستودون کشف شوید. ممکن است فرستههایتان در نتیحهٔ جستوجوها و فرستههای داغ ظاهر شده و نمایهتان به افرادی با علایق مشابهتان پیشنهاد شود.",
|
||||
"onboarding.profile.display_name": "نام نمایشی",
|
||||
"onboarding.profile.display_name_hint": "نام کامل یا نام باحالتان…",
|
||||
"onboarding.profile.lead": "همواره میتوانید این مورد را در تنظیمات که گزینهّای شخصی سازی بیشتری نیز دارد کامل کنید.",
|
||||
"onboarding.profile.note": "درباره شما",
|
||||
"onboarding.profile.note_hint": "میتوانید افراد دیگر را @نامبردن یا #برچسب بزنید…",
|
||||
"onboarding.profile.save_and_continue": "ذخیره کن و ادامه بده",
|
||||
|
@ -522,6 +535,7 @@
|
|||
"privacy.private.short": "پیگیرندگان",
|
||||
"privacy.public.long": "هرکسی در و بیرون از ماستودون",
|
||||
"privacy.public.short": "عمومی",
|
||||
"privacy.unlisted.additional": "درست مثل عمومی رفتار میکند؛ جز این که فرسته در برچسبها یا خوراکهای زنده، کشف یا جستوجوی ماستودون ظاهر نخواهد شد. حتا اگر کلیّت نمایهتان اجازه داده باشد.",
|
||||
"privacy.unlisted.long": "سروصدای الگوریتمی کمتر",
|
||||
"privacy.unlisted.short": "عمومی ساکت",
|
||||
"privacy_policy.last_updated": "آخرین بهروز رسانی در {date}",
|
||||
|
@ -541,6 +555,7 @@
|
|||
"relative_time.minutes": "{number} دقیقه",
|
||||
"relative_time.seconds": "{number} ثانیه",
|
||||
"relative_time.today": "امروز",
|
||||
"reply_indicator.attachments": "{count, plural, one {# پیوست} other {# پیوست}}",
|
||||
"reply_indicator.cancel": "لغو",
|
||||
"reply_indicator.poll": "نظرسنجی",
|
||||
"report.block": "انسداد",
|
||||
|
|
|
@ -212,7 +212,7 @@
|
|||
"emoji_button.custom": "사용자 지정",
|
||||
"emoji_button.flags": "깃발",
|
||||
"emoji_button.food": "음식과 마실것",
|
||||
"emoji_button.label": "에모지를 추가",
|
||||
"emoji_button.label": "에모지 추가",
|
||||
"emoji_button.nature": "자연",
|
||||
"emoji_button.not_found": "해당하는 에모지가 없습니다",
|
||||
"emoji_button.objects": "물건",
|
||||
|
|
|
@ -277,7 +277,11 @@
|
|||
"follow_request.authorize": "Benarkan",
|
||||
"follow_request.reject": "Tolak",
|
||||
"follow_requests.unlocked_explanation": "Walaupun akaun anda tidak dikunci, kakitangan {domain} merasakan anda mungkin ingin menyemak permintaan ikutan daripada akaun ini secara manual.",
|
||||
"follow_suggestions.curated_suggestion": "",
|
||||
"follow_suggestions.dismiss": "Jangan papar lagi",
|
||||
"follow_suggestions.hints.featured": "Profil{domain.",
|
||||
"follow_suggestions.hints.friends_of_friends": "This profile is popular among the people you follow.",
|
||||
"follow_suggestions.hints.most_followed": ".",
|
||||
"follow_suggestions.personalized_suggestion": "Cadangan peribadi",
|
||||
"follow_suggestions.popular_suggestion": "Cadangan terkenal",
|
||||
"follow_suggestions.view_all": "Lihat semua",
|
||||
|
|
|
@ -40,7 +40,7 @@
|
|||
"account.following_counter": "{count, plural, one {Fylgjer {counter}} other {Fylgjer {counter}}}",
|
||||
"account.follows.empty": "Denne brukaren fylgjer ikkje nokon enno.",
|
||||
"account.go_to_profile": "Gå til profil",
|
||||
"account.hide_reblogs": "Skjul framhevingar frå @{name}",
|
||||
"account.hide_reblogs": "Gøym framhevingar frå @{name}",
|
||||
"account.in_memoriam": "Til minne om.",
|
||||
"account.joined_short": "Vart med",
|
||||
"account.languages": "Endre språktingingar",
|
||||
|
@ -113,7 +113,7 @@
|
|||
"column.community": "Lokal tidsline",
|
||||
"column.direct": "Private omtaler",
|
||||
"column.directory": "Sjå gjennom profilar",
|
||||
"column.domain_blocks": "Skjulte domene",
|
||||
"column.domain_blocks": "Blokkerte domene",
|
||||
"column.favourites": "Favorittar",
|
||||
"column.firehose": "Tidslinjer",
|
||||
"column.follow_requests": "Fylgjeførespurnadar",
|
||||
|
@ -124,7 +124,7 @@
|
|||
"column.pins": "Festa tut",
|
||||
"column.public": "Samla tidsline",
|
||||
"column_back_button.label": "Attende",
|
||||
"column_header.hide_settings": "Gøym innstillingar",
|
||||
"column_header.hide_settings": "Gøym innstillingane",
|
||||
"column_header.moveLeft_settings": "Flytt kolonne til venstre",
|
||||
"column_header.moveRight_settings": "Flytt kolonne til høgre",
|
||||
"column_header.pin": "Fest",
|
||||
|
@ -171,14 +171,14 @@
|
|||
"confirmations.delete_list.message": "Er du sikker på at du vil sletta denne lista for alltid?",
|
||||
"confirmations.discard_edit_media.confirm": "Forkast",
|
||||
"confirmations.discard_edit_media.message": "Du har ulagra endringar i mediaskildringa eller førehandsvisinga. Vil du forkasta dei likevel?",
|
||||
"confirmations.domain_block.confirm": "Skjul alt frå domenet",
|
||||
"confirmations.domain_block.confirm": "Blokker heile domenet",
|
||||
"confirmations.domain_block.message": "Er du heilt, heilt sikker på at du vil skjula heile {domain}? I dei fleste tilfelle er det godt nok og føretrekt med nokre få målretta blokkeringar eller målbindingar. Du kjem ikkje til å sjå innhald frå domenet i fødererte tidsliner eller i varsla dine. Fylgjarane dine frå domenet vert fjerna.",
|
||||
"confirmations.edit.confirm": "Rediger",
|
||||
"confirmations.edit.message": "Å redigera no vil overskriva den meldinga du er i ferd med å skriva. Er du sikker på at du vil halda fram?",
|
||||
"confirmations.logout.confirm": "Logg ut",
|
||||
"confirmations.logout.message": "Er du sikker på at du vil logga ut?",
|
||||
"confirmations.mute.confirm": "Målbind",
|
||||
"confirmations.mute.explanation": "Dette vil skjula innlegg som kjem frå og som nemner dei, men vil framleis la dei sjå innlegga dine og fylgje deg.",
|
||||
"confirmations.mute.explanation": "Dette vil gøyma innlegga deira og innlegg som nemner dei, men dei vil framleis kunna sjå innlegga dine og fylgja deg.",
|
||||
"confirmations.mute.message": "Er du sikker på at du vil målbinda {name}?",
|
||||
"confirmations.redraft.confirm": "Slett & skriv på nytt",
|
||||
"confirmations.redraft.message": "Er du sikker på at du vil sletta denne statusen og skriva han på nytt? Då misser du favorittar og framhevingar, og svar til det opprinnelege innlegget vert foreldrelause.",
|
||||
|
@ -230,7 +230,7 @@
|
|||
"empty_column.bookmarked_statuses": "Du har ikkje lagra noko bokmerke enno. Når du set bokmerke på eit innlegg, dukkar det opp her.",
|
||||
"empty_column.community": "Den lokale tidslina er tom. Skriv noko offentleg å få ballen til å rulle!",
|
||||
"empty_column.direct": "Du har ingen private omtaler enda. Etter du har sendt eller mottatt en, så vil den dukke opp her.",
|
||||
"empty_column.domain_blocks": "Det er ingen skjulte domene til no.",
|
||||
"empty_column.domain_blocks": "Det er ingen blokkerte domene enno.",
|
||||
"empty_column.explore_statuses": "Ingenting er i støytet nett no. Prøv igjen seinare!",
|
||||
"empty_column.favourited_statuses": "Du har ingen favoritt-statusar ennå. Når du merkjer ein som favoritt, dukkar han opp her.",
|
||||
"empty_column.favourites": "Ingen har merkt denne statusen som favoritt enno. Når nokon gjer det, dukkar dei opp her.",
|
||||
|
@ -277,7 +277,13 @@
|
|||
"follow_request.authorize": "Autoriser",
|
||||
"follow_request.reject": "Avvis",
|
||||
"follow_requests.unlocked_explanation": "Sjølv om kontoen din ikkje er låst tenkte dei som driv {domain} at du kanskje ville gå gjennom førespurnadar frå desse kontoane manuelt.",
|
||||
"follow_suggestions.curated_suggestion": "Utvalt av staben",
|
||||
"follow_suggestions.dismiss": "Ikkje vis igjen",
|
||||
"follow_suggestions.hints.featured": "Denne profilen er handplukka av folka på {domain}.",
|
||||
"follow_suggestions.hints.friends_of_friends": "Denne profilen er populær hjå dei du fylgjer.",
|
||||
"follow_suggestions.hints.most_followed": "Mange på {domain} fylgjer denne profilen.",
|
||||
"follow_suggestions.hints.most_interactions": "Denne profilen har nyss fått mykje merksemd på {domain}.",
|
||||
"follow_suggestions.hints.similar_to_recently_followed": "Denne profilen liknar på dei andre profilane du har fylgt i det siste.",
|
||||
"follow_suggestions.personalized_suggestion": "Personleg forslag",
|
||||
"follow_suggestions.popular_suggestion": "Populært forslag",
|
||||
"follow_suggestions.view_all": "Vis alle",
|
||||
|
@ -395,7 +401,7 @@
|
|||
"media_gallery.toggle_visible": "{number, plural, one {Skjul bilete} other {Skjul bilete}}",
|
||||
"moved_to_account_banner.text": "Kontoen din, {disabledAccount} er for tida deaktivert fordi du har flytta til {movedToAccount}.",
|
||||
"mute_modal.duration": "Varigheit",
|
||||
"mute_modal.hide_notifications": "Skjul varsel frå denne brukaren?",
|
||||
"mute_modal.hide_notifications": "Gøym varsel frå denne brukaren?",
|
||||
"mute_modal.indefinite": "På ubestemt tid",
|
||||
"navigation_bar.about": "Om",
|
||||
"navigation_bar.advanced_interface": "Opne i avansert nettgrensesnitt",
|
||||
|
@ -479,7 +485,8 @@
|
|||
"onboarding.follows.empty": "Me kan ikkje visa deg nokon resultat no. Du kan prøva å søkja eller bla gjennom utforsk-sida for å finna folk å fylgja, eller du kan prøva att seinare.",
|
||||
"onboarding.follows.lead": "You curate your own home feed. The more people you follow, the more active and interesting it will be. These profiles may be a good starting point—you can always unfollow them later!",
|
||||
"onboarding.follows.title": "Popular on Mastodon",
|
||||
"onboarding.profile.discoverable": "Gjør min profil synlig",
|
||||
"onboarding.profile.discoverable": "Gjer profilen min synleg",
|
||||
"onboarding.profile.discoverable_hint": "Når du vel å gjera profilen din synleg på Mastodon, vil innlegga dine syna i søkjeresultat og populære innlegg, og profilen din kan bli føreslegen for folk med liknande interesser som deg.",
|
||||
"onboarding.profile.display_name": "Synleg namn",
|
||||
"onboarding.profile.display_name_hint": "Det fulle namnet eller kallenamnet ditt…",
|
||||
"onboarding.profile.lead": "Du kan alltid fullføra dette seinare i innstillingane, og der er det endå fleire tilpassingsalternativ.",
|
||||
|
@ -528,11 +535,12 @@
|
|||
"privacy.private.short": "Følgjarar",
|
||||
"privacy.public.long": "Kven som helst på og av Mastodon",
|
||||
"privacy.public.short": "Offentleg",
|
||||
"privacy.unlisted.additional": "Dette er akkurat som offentleg, bortsett frå at innlegga ikkje dukkar opp i direktestraumar eller merkelappar, i oppdagingar eller Mastodon-søk, sjølv om du har sagt ja til at kontoen skal vera synleg.",
|
||||
"privacy.unlisted.long": "Færre algoritmiske fanfarar",
|
||||
"privacy.unlisted.short": "Stille offentleg",
|
||||
"privacy_policy.last_updated": "Sist oppdatert {date}",
|
||||
"privacy_policy.title": "Personvernsreglar",
|
||||
"recommended": "Anbefalt",
|
||||
"recommended": "Tilrådd",
|
||||
"refresh": "Oppdater",
|
||||
"regeneration_indicator.label": "Lastar…",
|
||||
"regeneration_indicator.sublabel": "Heimetidslina di vert førebudd!",
|
||||
|
@ -605,7 +613,7 @@
|
|||
"search.quick_action.status_search": "Innlegg som samsvarer med {x}",
|
||||
"search.search_or_paste": "Søk eller lim inn URL",
|
||||
"search_popout.full_text_search_disabled_message": "Ikkje tilgjengeleg på {domain}.",
|
||||
"search_popout.full_text_search_logged_out_message": "Bare tilgjengelig når man er logget inn.",
|
||||
"search_popout.full_text_search_logged_out_message": "Berre tilgjengeleg når du er logga inn.",
|
||||
"search_popout.language_code": "ISO-språkkode",
|
||||
"search_popout.options": "Søkjealternativ",
|
||||
"search_popout.quick_actions": "Hurtighandlinger",
|
||||
|
@ -654,7 +662,7 @@
|
|||
"status.load_more": "Last inn meir",
|
||||
"status.media.open": "Klikk for å opne",
|
||||
"status.media.show": "Klikk for å vise",
|
||||
"status.media_hidden": "Medium gøymd",
|
||||
"status.media_hidden": "Mediet er gøymt",
|
||||
"status.mention": "Nemn @{name}",
|
||||
"status.more": "Meir",
|
||||
"status.mute": "Målbind @{name}",
|
||||
|
|
|
@ -40,7 +40,7 @@ function render(
|
|||
ui: React.ReactElement,
|
||||
{ locale = 'en', signedIn = true, ...renderOptions } = {},
|
||||
) {
|
||||
const Wrapper = (props: { children: React.ReactElement }) => {
|
||||
const Wrapper = (props: { children: React.ReactNode }) => {
|
||||
return (
|
||||
<MemoryRouter>
|
||||
<IntlProvider locale={locale}>
|
||||
|
|
|
@ -46,7 +46,7 @@ const hideSelectAll = () => {
|
|||
Rails.delegate(document, '#batch_checkbox_all', 'change', ({ target }) => {
|
||||
const selectAllMatchingElement = document.querySelector('.batch-table__select-all');
|
||||
|
||||
[].forEach.call(document.querySelectorAll(batchCheckboxClassName), (content) => {
|
||||
document.querySelectorAll(batchCheckboxClassName).forEach((content) => {
|
||||
content.checked = target.checked;
|
||||
});
|
||||
|
||||
|
@ -81,8 +81,11 @@ Rails.delegate(document, batchCheckboxClassName, 'change', () => {
|
|||
const selectAllMatchingElement = document.querySelector('.batch-table__select-all');
|
||||
|
||||
if (checkAllElement) {
|
||||
checkAllElement.checked = [].every.call(document.querySelectorAll(batchCheckboxClassName), (content) => content.checked);
|
||||
checkAllElement.indeterminate = !checkAllElement.checked && [].some.call(document.querySelectorAll(batchCheckboxClassName), (content) => content.checked);
|
||||
const allCheckboxes = Array.from(
|
||||
document.querySelectorAll(batchCheckboxClassName)
|
||||
);
|
||||
checkAllElement.checked = allCheckboxes.every((content) => content.checked);
|
||||
checkAllElement.indeterminate = !checkAllElement.checked && allCheckboxes.some((content) => content.checked);
|
||||
|
||||
if (selectAllMatchingElement) {
|
||||
if (checkAllElement.checked) {
|
||||
|
@ -143,11 +146,11 @@ Rails.delegate(document, '#form_admin_settings_enable_bootstrap_timeline_account
|
|||
const onChangeRegistrationMode = (target) => {
|
||||
const enabled = target.value === 'approved';
|
||||
|
||||
[].forEach.call(document.querySelectorAll('.form_admin_settings_registrations_mode .warning-hint'), (warning_hint) => {
|
||||
document.querySelectorAll('.form_admin_settings_registrations_mode .warning-hint').forEach((warning_hint) => {
|
||||
warning_hint.style.display = target.value === 'open' ? 'inline' : 'none';
|
||||
});
|
||||
|
||||
[].forEach.call(document.querySelectorAll('#form_admin_settings_require_invite_text'), (input) => {
|
||||
document.querySelectorAll('#form_admin_settings_require_invite_text').forEach((input) => {
|
||||
input.disabled = !enabled;
|
||||
if (enabled) {
|
||||
let element = input;
|
||||
|
@ -193,8 +196,9 @@ ready(() => {
|
|||
|
||||
const checkAllElement = document.querySelector('#batch_checkbox_all');
|
||||
if (checkAllElement) {
|
||||
checkAllElement.checked = [].every.call(document.querySelectorAll(batchCheckboxClassName), (content) => content.checked);
|
||||
checkAllElement.indeterminate = !checkAllElement.checked && [].some.call(document.querySelectorAll(batchCheckboxClassName), (content) => content.checked);
|
||||
const allCheckboxes = Array.from(document.querySelectorAll(batchCheckboxClassName));
|
||||
checkAllElement.checked = allCheckboxes.every( (content) => content.checked);
|
||||
checkAllElement.indeterminate = !checkAllElement.checked && allCheckboxes.some((content) => content.checked);
|
||||
}
|
||||
|
||||
document.querySelector('a#add-instance-button')?.addEventListener('click', (e) => {
|
||||
|
@ -207,7 +211,7 @@ ready(() => {
|
|||
}
|
||||
});
|
||||
|
||||
[].forEach.call(document.querySelectorAll('input[type="datetime-local"]'), element => {
|
||||
document.querySelectorAll('input[type="datetime-local"]').forEach(element => {
|
||||
if (element.value) {
|
||||
element.value = convertUTCDateTimeToLocal(element.value);
|
||||
}
|
||||
|
@ -217,7 +221,7 @@ ready(() => {
|
|||
});
|
||||
|
||||
Rails.delegate(document, 'form', 'submit', ({ target }) => {
|
||||
[].forEach.call(target.querySelectorAll('input[type="datetime-local"]'), element => {
|
||||
target.querySelectorAll('input[type="datetime-local"]').forEach(element => {
|
||||
if (element.value && element.validity.valid) {
|
||||
element.value = convertLocalDatetimeToUTC(element.value);
|
||||
}
|
||||
|
@ -229,7 +233,7 @@ ready(() => {
|
|||
setAnnouncementEndsAttributes(announcementStartsAt);
|
||||
}
|
||||
|
||||
[].forEach.call(document.querySelectorAll('[data-admin-component]'), element => {
|
||||
document.querySelectorAll('[data-admin-component]').forEach(element => {
|
||||
const componentName = element.getAttribute('data-admin-component');
|
||||
const componentProps = JSON.parse(element.getAttribute('data-props'));
|
||||
|
||||
|
|
|
@ -73,11 +73,11 @@ function loaded() {
|
|||
return messageFormat.format(values);
|
||||
};
|
||||
|
||||
[].forEach.call(document.querySelectorAll('.emojify'), (content) => {
|
||||
document.querySelectorAll('.emojify').forEach((content) => {
|
||||
content.innerHTML = emojify(content.innerHTML);
|
||||
});
|
||||
|
||||
[].forEach.call(document.querySelectorAll('time.formatted'), (content) => {
|
||||
document.querySelectorAll('time.formatted').forEach((content) => {
|
||||
const datetime = new Date(content.getAttribute('datetime'));
|
||||
const formattedDate = dateTimeFormat.format(datetime);
|
||||
|
||||
|
@ -94,7 +94,7 @@ function loaded() {
|
|||
};
|
||||
const todayFormat = new IntlMessageFormat(localeData['relative_format.today'] || 'Today at {time}', locale);
|
||||
|
||||
[].forEach.call(document.querySelectorAll('time.relative-formatted'), (content) => {
|
||||
document.querySelectorAll('time.relative-formatted').forEach((content) => {
|
||||
const datetime = new Date(content.getAttribute('datetime'));
|
||||
|
||||
let formattedContent;
|
||||
|
@ -111,7 +111,7 @@ function loaded() {
|
|||
content.textContent = formattedContent;
|
||||
});
|
||||
|
||||
[].forEach.call(document.querySelectorAll('time.time-ago'), (content) => {
|
||||
document.querySelectorAll('time.time-ago').forEach((content) => {
|
||||
const datetime = new Date(content.getAttribute('datetime'));
|
||||
const now = new Date();
|
||||
|
||||
|
@ -128,8 +128,8 @@ function loaded() {
|
|||
if (reactComponents.length > 0) {
|
||||
import(/* webpackChunkName: "containers/media_container" */ '../mastodon/containers/media_container')
|
||||
.then(({ default: MediaContainer }) => {
|
||||
[].forEach.call(reactComponents, (component) => {
|
||||
[].forEach.call(component.children, (child) => {
|
||||
reactComponents.forEach((component) => {
|
||||
Array.from(component.children).forEach((child) => {
|
||||
component.removeChild(child);
|
||||
});
|
||||
});
|
||||
|
@ -185,7 +185,7 @@ function loaded() {
|
|||
return false;
|
||||
});
|
||||
|
||||
[].forEach.call(document.querySelectorAll('.status__content__spoiler-link'), (spoilerLink) => {
|
||||
document.querySelectorAll('.status__content__spoiler-link').forEach((spoilerLink) => {
|
||||
const statusEl = spoilerLink.parentNode.parentNode;
|
||||
const message = (statusEl.dataset.spoiler === 'expanded') ? (localeData['status.show_less'] || 'Show less') : (localeData['status.show_more'] || 'Show more');
|
||||
spoilerLink.textContent = (new IntlMessageFormat(message, locale)).format();
|
||||
|
|
|
@ -324,6 +324,23 @@ $content-width: 840px;
|
|||
padding-bottom: 0;
|
||||
margin-bottom: 0;
|
||||
border-bottom: 0;
|
||||
|
||||
.comment {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
margin-top: 4px;
|
||||
|
||||
&.private-comment {
|
||||
display: block;
|
||||
color: $darker-text-color;
|
||||
}
|
||||
|
||||
&.public-comment {
|
||||
display: block;
|
||||
color: $secondary-text-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
& > p {
|
||||
|
@ -1044,6 +1061,7 @@ a.name-tag,
|
|||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin-bottom: 0;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
&__permissions {
|
||||
|
|
|
@ -5479,6 +5479,7 @@ a.status-card {
|
|||
color: $darker-text-color;
|
||||
cursor: default;
|
||||
pointer-events: none;
|
||||
margin-inline-start: 16px - 2px;
|
||||
|
||||
&.active {
|
||||
pointer-events: auto;
|
||||
|
|
|
@ -1079,6 +1079,7 @@ code {
|
|||
|
||||
&__type {
|
||||
color: $darker-text-color;
|
||||
word-break: break-word;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue