Merge pull request #956 from cheeaun/main

Update from main
This commit is contained in:
Chee Aun 2024-12-08 19:50:33 +08:00 committed by GitHub
commit 7e1ffc5211
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
52 changed files with 15074 additions and 13973 deletions

View file

@ -273,6 +273,7 @@ These are self-hosted by other wonderful folks.
- [phanpy.tilde.zone](https://phanpy.tilde.zone) by [@ben@tilde.zone](https://tilde.zone/@ben)
- [phanpy.vmst.io](https://phanpy.vmst.io/) by [@vmstan@vmst.io](https://vmst.io/@vmstan)
- [social.qrk.one](https://social.qrk.one) by [@kev@fosstodon.org](https://fosstodon.org/@kev)
- [phanpy.linuxusers.in](https://phanpy.linuxusers.in) by [@dharmik@linuxusers.in](https://linuxusers.in/dharmik)
> Note: Add yours by creating a pull request.
@ -324,12 +325,14 @@ Costs involved in running and developing this web app:
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/16529521/medium/ae6add93a901b0fefa2d9b1077920d73.png" alt="" width="16" height="16" /> llun (Thai)
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/16291756/medium/c008af10bc117fa9c9dcb70f2b291ee6.jpg" alt="" width="16" height="16" /> lucasofchirst (Occitan, Portuguese, Portuguese, Brazilian)
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/16640089/medium/4b7d8d275d7a7bff564adde51e09b473_default.png" alt="" width="16" height="16" /> LukeHong (Chinese Traditional)
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/12822971/medium/4ecbe6d1248536084902925beb0b63e4.png" alt="" width="16" height="16" /> Mannivu (Italian)
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/16537713/medium/825f0bf1a14fc545a76891a52839d86e_default.png" alt="" width="16" height="16" /> marcin.kozinski (Polish)
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/13521465/medium/76cb9aa6b753ce900a70478bff7fcea0.png" alt="" width="16" height="16" /> mkljczkk (Polish)
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/12882812/medium/77744d8db46e9a3e09030e1a02b7a572.jpeg" alt="" width="16" height="16" /> mojosoeun (Korean)
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/13613969/medium/c7834ddc0ada84a79671697a944bb274.png" alt="" width="16" height="16" /> moreal (Korean)
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/14158861/medium/ba1ff31dc5743b067ea6685f735229a5_default.png" alt="" width="16" height="16" /> MrWillCom (Chinese Simplified)
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/15652333/medium/7f36f289f9e2fe41d89ad534a1047f0e.png" alt="" width="16" height="16" /> nclm (French)
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/15000639/medium/ebbf0bb7d5027a1903d11b7f5f34f65b.jpeg" alt="" width="16" height="16" /> nycterent (Lithuanian)
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/16539461/medium/2f41b9f0b802c1d200a6ab62167a7229_default.png" alt="" width="16" height="16" /> pazpi (Italian)
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/13954917/medium/56a2cba267eb1b5d122bf62ddc0dd732_default.png" alt="" width="16" height="16" /> PPNplus (Thai)
- <img src="https://crowdin-static.downloads.crowdin.com/avatar/15106977/medium/54bf93b19af8bbfdee579ea51685bafa.jpeg" alt="" width="16" height="16" /> punkrockgirl (Basque)

13
package-lock.json generated
View file

@ -58,6 +58,7 @@
"postcss": "~8.4.49",
"postcss-dark-theme-class": "~1.3.0",
"postcss-preset-env": "~10.1.1",
"prettier": "3.4.1",
"sonda": "~0.6.1",
"twitter-text": "~3.1.0",
"vite": "~5.4.11",
@ -8406,17 +8407,15 @@
}
},
"node_modules/prettier": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.0.tgz",
"integrity": "sha512-9Lmg8hTFZKG0Asr/kW9Bp8tJjRVluO8EJQVfY2T7FMw9T5jy4I/Uvx0Rca/XWf50QQ1/SS48+6IJWnrb+2yemA==",
"version": "3.4.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.1.tgz",
"integrity": "sha512-G+YdqtITVZmOJje6QkXQWzl3fSfMxFwm1tjTyo9exhkmWSqC4Yhd1+lug++IlR2mvRVAxEDDWYkQdeSztajqgg==",
"dev": true,
"license": "MIT",
"peer": true,
"bin": {
"prettier": "bin-prettier.js"
"prettier": "bin/prettier.cjs"
},
"engines": {
"node": ">=10.13.0"
"node": ">=14"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"

View file

@ -66,6 +66,7 @@
"postcss": "~8.4.49",
"postcss-dark-theme-class": "~1.3.0",
"postcss-preset-env": "~10.1.1",
"prettier": "3.4.1",
"sonda": "~0.6.1",
"twitter-text": "~3.1.0",
"vite": "~5.4.11",

View file

@ -27,6 +27,7 @@ import SearchCommand from './components/search-command';
import Shortcuts from './components/shortcuts';
import NotFound from './pages/404';
import AccountStatuses from './pages/account-statuses';
import AnnualReport from './pages/annual-report';
import Bookmarks from './pages/bookmarks';
import Catchup from './pages/catchup';
import Favourites from './pages/favourites';
@ -98,7 +99,8 @@ window.__STATES_STATS__ = () => {
// Experimental "garbage collection" for states
// Every 15 minutes
// Only posts for now
setInterval(() => {
setInterval(
() => {
if (!window.__IDLE__) return;
const { statuses, unfurledLinks, notifications } = states;
let keysCount = 0;
@ -130,7 +132,9 @@ setInterval(() => {
if (keysCount) {
console.info(`GC: Removed ${keysCount} keys`);
}
}, 15 * 60 * 1000);
},
15 * 60 * 1000,
);
// Preload icons
// There's probably a better way to do this
@ -546,6 +550,7 @@ function SecondaryRoutes({ isLoggedIn }) {
<Route path="/fh" element={<FollowedHashtags />} />
<Route path="/ft" element={<Filters />} />
<Route path="/catchup" element={<Catchup />} />
<Route path="/annual_report/:year" element={<AnnualReport />} />
</>
)}
<Route path="/:instance?/t/:hashtag" element={<Hashtag />} />

View file

@ -174,4 +174,5 @@ export const ICONS = {
'heart-break': () => import('@iconify-icons/mingcute/heart-crack-line'),
'user-x': () => import('@iconify-icons/mingcute/user-x-line'),
minimize: () => import('@iconify-icons/mingcute/arrows-down-line'),
celebrate: () => import('@iconify-icons/mingcute/celebrate-line'),
};

View file

@ -20,11 +20,15 @@
justify-content: space-between;
gap: 8px;
align-items: center;
padding: 16px;
padding: 8px;
position: sticky;
top: 0;
z-index: 100;
white-space: nowrap;
@media (min-width: 480px) {
padding: 16px;
}
}
#compose-container .compose-top .account-block {
text-align: start;
@ -110,10 +114,10 @@
}
#compose-container form {
--form-padding-inline: 8px;
--form-padding-block: 0;
--form-spacing-inline: 4px;
--form-spacing-block: 0;
/* border-radius: 16px; */
padding: var(--form-padding-block) var(--form-padding-inline);
padding: var(--form-spacing-block) var(--form-spacing-inline);
background-color: var(--bg-blur-color);
/* background-image: linear-gradient(var(--bg-color) 85%, transparent); */
position: relative;
@ -121,6 +125,10 @@
--drop-shadow: 0 3px 6px -3px var(--drop-shadow-color);
box-shadow: var(--drop-shadow);
@media (min-width: 480px) {
--form-spacing-inline: 8px;
}
@media (min-width: 40em) {
border-radius: 16px;
}
@ -153,8 +161,8 @@
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 0;
gap: 8px;
padding: var(--form-spacing-inline) 0;
gap: var(--form-spacing-inline);
}
#compose-container .toolbar.wrap {
flex-wrap: wrap;
@ -181,6 +189,11 @@
white-space: nowrap;
border: 2px solid transparent;
vertical-align: middle;
&.active {
filter: brightness(0.8);
background-color: var(--bg-color);
}
}
#compose-container .toolbar-button > * {
vertical-align: middle;
@ -246,6 +259,39 @@
text-overflow: ellipsis;
overflow: hidden;
max-width: 100%;
min-width: 4ch;
}
#compose-container .compose-footer {
.add-toolbar-button-group {
display: flex;
overflow: auto;
}
.add-sub-toolbar-button-group {
flex-grow: 1;
display: flex;
overflow: auto;
transition: 0.5s ease-in-out;
transition-property: opacity, width;
scrollbar-width: none;
padding-inline-end: 16px;
mask-image: linear-gradient(
var(--to-backward),
transparent 0,
black 16px,
black 100%
);
&::-webkit-scrollbar {
display: none;
}
&[hidden] {
opacity: 0;
pointer-events: none;
width: 0;
}
}
}
#compose-container text-expander {
@ -516,6 +562,37 @@
color: var(--red-color);
}
.compose-menu-add-media {
position: relative;
.compose-menu-add-media-field {
position: absolute;
inset: 0;
opacity: 0;
cursor: inherit;
}
}
.icon-gif {
display: inline-block !important;
min-width: 16px;
height: 16px;
font-size: 10px !important;
letter-spacing: -0.5px;
font-size-adjust: none;
overflow: hidden;
white-space: nowrap;
text-align: center;
line-height: 16px;
font-weight: bold;
text-rendering: optimizeSpeed;
&:after {
display: block;
content: 'GIF';
}
}
@media (display-mode: standalone) {
/* No popping in standalone mode */
#compose-container .pop-button {
@ -525,8 +602,10 @@
#compose-container button[type='submit'] {
border-radius: 8px;
@media (min-width: 480px) {
padding-inline: 24px;
font-size: 125%;
}
}
@ -820,8 +899,8 @@
.compose-field-container {
display: grid !important;
@media (width < 30em) {
margin-inline: calc(-1 * var(--form-padding-inline));
@media (width < 480px) {
margin-inline: calc(-1 * var(--form-spacing-inline));
width: 100vw !important;
max-width: 100vw;
@ -929,15 +1008,55 @@
}
}
@keyframes jump-scare {
from {
opacity: 0.5;
transform: scale(0.25) translateX(80px);
}
to {
opacity: 1;
transform: scale(1) translateX(0);
}
}
@keyframes jump-scare-rtl {
from {
opacity: 0.5;
transform: scale(0.25) translateX(-80px);
}
to {
opacity: 1;
transform: scale(1) translateX(0);
}
}
.add-button {
transform-origin: var(--forward) center;
background-color: var(--bg-blur-color) !important;
animation: jump-scare 0.2s ease-in-out both;
:dir(rtl) & {
animation-name: jump-scare-rtl;
}
.icon {
transition: transform 0.3s ease-in-out;
}
&.active {
.icon {
transform: rotate(135deg);
}
}
}
.gif-picker-button {
span {
/* span {
font-weight: bold;
font-size: 11.5px;
display: block;
}
line-height: 1;
} */
&:is(:hover, :focus) {
span {
.icon {
animation: gif-shake 0.3s 3;
}
}

View file

@ -19,6 +19,7 @@ import stringLength from 'string-length';
// import { detectAll } from 'tinyld/light';
import { uid } from 'uid/single';
import { useDebouncedCallback, useThrottledCallback } from 'use-debounce';
import useResizeObserver from 'use-resize-observer';
import { useSnapshot } from 'valtio';
import poweredByGiphyURL from '../assets/powered-by-giphy.svg';
@ -201,6 +202,13 @@ const LF = mem((locale) => new Intl.ListFormat(locale || undefined));
const CUSTOM_EMOJIS_COUNT = 100;
const ADD_LABELS = {
media: msg`Add media`,
customEmoji: msg`Add custom emoji`,
gif: msg`Add GIF`,
poll: msg`Add poll`,
};
function Compose({
onClose,
replyToStatus,
@ -209,7 +217,7 @@ function Compose({
standalone,
hasOpener,
}) {
const { i18n } = useLingui();
const { i18n, _ } = useLingui();
const rtf = RTF(i18n.locale);
const lf = LF(i18n.locale);
@ -732,6 +740,39 @@ function Compose({
states.composerState.minimized = true;
};
const gifPickerDisabled =
uiState === 'loading' ||
(maxMediaAttachments !== undefined &&
mediaAttachments.length >= maxMediaAttachments) ||
!!poll;
// If maxOptions is not defined or defined and is greater than 1, show poll button
const showPollButton = maxOptions == null || maxOptions > 1;
const pollButtonDisabled =
uiState === 'loading' || !!poll || !!mediaAttachments.length;
const onPollButtonClick = () => {
setPoll({
options: ['', ''],
expiresIn: 24 * 60 * 60, // 1 day
multiple: false,
});
};
const addSubToolbarRef = useRef();
const [showAddButton, setShowAddButton] = useState(false);
useResizeObserver({
ref: addSubToolbarRef,
box: 'border-box',
onResize: ({ width }) => {
// If scrollable, it's truncated
const { scrollWidth } = addSubToolbarRef.current;
const truncated = scrollWidth > width;
const overTruncated = width < 84; // roughly two buttons width
setShowAddButton(overTruncated || truncated);
addSubToolbarRef.current.hidden = overTruncated;
},
});
return (
<div id="compose-container-outer">
<div id="compose-container" class={standalone ? 'standalone' : ''}>
@ -1318,86 +1359,88 @@ function Compose({
}}
/>
)}
<div
class="toolbar wrap"
style={{
justifyContent: 'flex-end',
<div class="toolbar compose-footer">
<span class="add-toolbar-button-group spacer">
{showAddButton && (
<Menu2
portal={{
target: document.body,
}}
containerProps={{
style: {
zIndex: 1001,
},
}}
menuButton={({ open }) => (
<button
type="button"
class={`toolbar-button add-button ${
open ? 'active' : ''
}`}
>
<span>
<label class="toolbar-button">
<input
type="file"
accept={supportedMimeTypes?.join(',')}
multiple={
maxMediaAttachments === undefined ||
maxMediaAttachments - mediaAttachments >= 2
}
<Icon icon="plus" title={t`Add`} />
</button>
)}
>
<MenuItem className="compose-menu-add-media">
<label class="compose-menu-add-media-field">
<FilePickerInput
hidden
supportedMimeTypes={supportedMimeTypes}
maxMediaAttachments={maxMediaAttachments}
mediaAttachments={mediaAttachments}
disabled={
uiState === 'loading' ||
mediaAttachments.length >= maxMediaAttachments ||
!!poll
}
onChange={(e) => {
const files = e.target.files;
if (!files) return;
const mediaFiles = Array.from(files).map((file) => ({
file,
type: file.type,
size: file.size,
url: URL.createObjectURL(file),
id: null, // indicate uploaded state
description: null,
}));
console.log('MEDIA ATTACHMENTS', files, mediaFiles);
// Validate max media attachments
if (
mediaAttachments.length + mediaFiles.length >
maxMediaAttachments
) {
alert(
plural(maxMediaAttachments, {
one: 'You can only attach up to 1 file.',
other: 'You can only attach up to # files.',
}),
);
} else {
setMediaAttachments((attachments) => {
return attachments.concat(mediaFiles);
});
}
// Reset
e.target.value = '';
}}
setMediaAttachments={setMediaAttachments}
/>
<Icon icon="attachment" />
</label>
{/* If maxOptions is not defined or defined and is greater than 1, show poll button */}
{maxOptions == null ||
(maxOptions > 1 && (
<>
<button
type="button"
class="toolbar-button"
disabled={
uiState === 'loading' ||
!!poll ||
!!mediaAttachments.length
}
<Icon icon="media" /> <span>{_(ADD_LABELS.media)}</span>
</MenuItem>
<MenuItem
onClick={() => {
setPoll({
options: ['', ''],
expiresIn: 24 * 60 * 60, // 1 day
multiple: false,
});
setShowEmoji2Picker(true);
}}
>
<Icon icon="poll" alt={t`Add poll`} />
</button>
</>
))}
<Icon icon="emoji2" />{' '}
<span>{_(ADD_LABELS.customEmoji)}</span>
</MenuItem>
{!!states.settings.composerGIFPicker && (
<MenuItem
disabled={gifPickerDisabled}
onClick={() => {
setShowGIFPicker(true);
}}
>
<span class="icon icon-gif" role="img" />
<span>{_(ADD_LABELS.gif)}</span>
</MenuItem>
)}
<MenuItem
disabled={pollButtonDisabled}
onClick={onPollButtonClick}
>
<Icon icon="poll" /> <span>{_(ADD_LABELS.poll)}</span>
</MenuItem>
</Menu2>
)}
<span class="add-sub-toolbar-button-group" ref={addSubToolbarRef}>
<label class="toolbar-button">
<FilePickerInput
supportedMimeTypes={supportedMimeTypes}
maxMediaAttachments={maxMediaAttachments}
mediaAttachments={mediaAttachments}
disabled={
uiState === 'loading' ||
mediaAttachments.length >= maxMediaAttachments ||
!!poll
}
setMediaAttachments={setMediaAttachments}
/>
<Icon icon="media" alt={_(ADD_LABELS.media)} />
</label>
{/* <button
type="button"
class="toolbar-button"
@ -1416,27 +1459,39 @@ function Compose({
setShowEmoji2Picker(true);
}}
>
<Icon icon="emoji2" alt={t`Add custom emoji`} />
<Icon icon="emoji2" alt={_(ADD_LABELS.customEmoji)} />
</button>
{!!states.settings.composerGIFPicker && (
<button
type="button"
class="toolbar-button gif-picker-button"
disabled={
uiState === 'loading' ||
(maxMediaAttachments !== undefined &&
mediaAttachments.length >= maxMediaAttachments) ||
!!poll
}
disabled={gifPickerDisabled}
onClick={() => {
setShowGIFPicker(true);
}}
>
<span>GIF</span>
<span
class="icon icon-gif"
aria-label={_(ADD_LABELS.gif)}
/>
</button>
)}
{}
{showPollButton && (
<>
<button
type="button"
class="toolbar-button"
disabled={pollButtonDisabled}
onClick={onPollButtonClick}
>
<Icon icon="poll" alt={_(ADD_LABELS.poll)} />
</button>
</>
)}
</span>
<div class="spacer" />
</span>
{/* <div class="spacer" /> */}
{uiState === 'loading' ? (
<Loader abrupt />
) : (
@ -1495,11 +1550,7 @@ function Compose({
})}
</select>
</label>{' '}
<button
type="submit"
class="large"
disabled={uiState === 'loading'}
>
<button type="submit" disabled={uiState === 'loading'}>
{replyToStatus
? t`Reply`
: editStatus
@ -1671,6 +1722,58 @@ function Compose({
);
}
function FilePickerInput({
hidden,
supportedMimeTypes,
maxMediaAttachments,
mediaAttachments,
disabled = false,
setMediaAttachments,
}) {
return (
<input
type="file"
hidden={hidden}
accept={supportedMimeTypes?.join(',')}
multiple={
maxMediaAttachments === undefined ||
maxMediaAttachments - mediaAttachments >= 2
}
disabled={disabled}
onChange={(e) => {
const files = e.target.files;
if (!files) return;
const mediaFiles = Array.from(files).map((file) => ({
file,
type: file.type,
size: file.size,
url: URL.createObjectURL(file),
id: null, // indicate uploaded state
description: null,
}));
console.log('MEDIA ATTACHMENTS', files, mediaFiles);
// Validate max media attachments
if (mediaAttachments.length + mediaFiles.length > maxMediaAttachments) {
alert(
plural(maxMediaAttachments, {
one: 'You can only attach up to 1 file.',
other: 'You can only attach up to # files.',
}),
);
} else {
setMediaAttachments((attachments) => {
return attachments.concat(mediaFiles);
});
}
// Reset
e.target.value = '';
}}
/>
);
}
function autoResizeTextarea(textarea) {
if (!textarea) return;
const { value, offsetHeight, scrollHeight, clientHeight } = textarea;

View file

@ -33,6 +33,7 @@ const NOTIFICATION_ICONS = {
moderation_warning: 'alert',
emoji_reaction: 'emoji2',
'pleroma:emoji_reaction': 'emoji2',
annual_report: 'celebrate',
};
/*
@ -261,6 +262,7 @@ const contentText = {
),
emoji_reaction: emojiText,
'pleroma:emoji_reaction': emojiText,
annual_report: ({ year }) => <Trans>Your {year} #Wrapstodon is here!</Trans>,
};
// account_suspension, domain_block, user_domain_block
@ -312,6 +314,7 @@ function Notification({
report,
event,
moderation_warning,
annualReport,
// Client-side grouped notification
_ids,
_accounts,
@ -409,6 +412,10 @@ function Notification({
emoji: notification.emoji,
emojiURL,
});
} else if (type === 'annual_report') {
text = text({
...notification.annualReport,
});
} else {
text = text({
account: account ? (
@ -527,6 +534,13 @@ function Notification({
</a>
</div>
)}
{type === 'annual_report' && (
<div>
<Link to={`/annual_report/${annualReport?.year}`}>
<Trans>View #Wrapstodon</Trans>
</Link>
</div>
)}
</>
)}
{_accounts?.length > 1 && (

View file

@ -15,7 +15,7 @@ import { shallowEqual } from 'fast-equals';
import prettify from 'html-prettify';
import pThrottle from 'p-throttle';
import { Fragment } from 'preact';
import { memo } from 'preact/compat';
import { forwardRef, memo } from 'preact/compat';
import {
useCallback,
useContext,
@ -2403,6 +2403,7 @@ function Status({
disabled={!canBoost}
/>
</div> */}
<div class="action has-count">
<MenuConfirm
disabled={!canBoost}
onClick={confirmBoostStatus}
@ -2438,7 +2439,6 @@ function Status({
)
}
>
<div class="action has-count">
<StatusButton
checked={reblogged}
title={[t`Boost`, t`Unboost`]}
@ -2449,8 +2449,8 @@ function Status({
// onClick={boostStatus}
disabled={!canBoost}
/>
</div>
</MenuConfirm>
</div>
<div class="action has-count">
<StatusButton
checked={favourited}
@ -3426,7 +3426,8 @@ function EmbedModal({ post, instance, onClose }) {
);
}
function StatusButton({
const StatusButton = forwardRef((props, ref) => {
let {
checked,
count,
class: className,
@ -3436,8 +3437,8 @@ function StatusButton({
icon,
iconSize = 'l',
onClick,
...props
}) {
...otherProps
} = props;
if (typeof title === 'string') {
title = [title, title];
}
@ -3460,6 +3461,7 @@ function StatusButton({
return (
<button
ref={ref}
type="button"
title={buttonTitle}
class={`plain ${size ? 'small' : ''} ${className} ${
@ -3471,7 +3473,7 @@ function StatusButton({
e.stopPropagation();
onClick(e);
}}
{...props}
{...otherProps}
>
<Icon icon={icon} size={iconSize} alt={iconAlt} />
{!!count && (
@ -3482,7 +3484,7 @@ function StatusButton({
)}
</button>
);
}
});
function nicePostURL(url) {
if (!url) return;

View file

@ -3,7 +3,7 @@
"code": "ar-SA",
"nativeName": "العربية",
"name": "Arabic",
"completion": 26
"completion": 25
},
{
"code": "ca-ES",
@ -21,7 +21,7 @@
"code": "de-DE",
"nativeName": "Deutsch",
"name": "German",
"completion": 95
"completion": 94
},
{
"code": "eo-UY",
@ -57,13 +57,13 @@
"code": "fr-FR",
"nativeName": "français",
"name": "French",
"completion": 98
"completion": 97
},
{
"code": "gl-ES",
"nativeName": "galego",
"name": "Galician",
"completion": 99
"completion": 100
},
{
"code": "he-IL",
@ -75,31 +75,31 @@
"code": "it-IT",
"nativeName": "italiano",
"name": "Italian",
"completion": 99
"completion": 100
},
{
"code": "ja-JP",
"nativeName": "日本語",
"name": "Japanese",
"completion": 52
"completion": 51
},
{
"code": "kab",
"nativeName": "Taqbaylit",
"name": "Kabyle",
"completion": 99
"completion": 98
},
{
"code": "ko-KR",
"nativeName": "한국어",
"name": "Korean",
"completion": 96
"completion": 95
},
{
"code": "lt-LT",
"nativeName": "lietuvių",
"name": "Lithuanian",
"completion": 97
"completion": 98
},
{
"code": "nb-NO",

View file

@ -5,5 +5,6 @@
"@mastodon/filtered-notifications": "~4.3 || >=4.3",
"@mastodon/fetch-multiple-statuses": "~4.3 || >=4.3",
"@mastodon/trending-link-posts": "~4.3 || >=4.3",
"@mastodon/grouped-notifications": "~4.3 || >=4.3"
"@mastodon/grouped-notifications": "~4.3 || >=4.3",
"@mastodon/annual-report": "~4.4 || >=4.4"
}

1173
src/locales/ar-SA.po generated

File diff suppressed because it is too large Load diff

561
src/locales/ca-ES.po generated

File diff suppressed because it is too large Load diff

1173
src/locales/cs-CZ.po generated

File diff suppressed because it is too large Load diff

1173
src/locales/de-DE.po generated

File diff suppressed because it is too large Load diff

383
src/locales/en.po generated
View file

@ -104,7 +104,7 @@ msgstr ""
#: src/components/account-info.jsx:429
#: src/components/account-info.jsx:1120
#: src/components/compose.jsx:2488
#: src/components/compose.jsx:2591
#: src/components/media-alt-modal.jsx:45
#: src/components/media-modal.jsx:357
#: src/components/status.jsx:1737
@ -399,11 +399,11 @@ msgstr ""
#: src/components/account-info.jsx:1994
#: src/components/account-info.jsx:2094
#: src/components/account-sheet.jsx:37
#: src/components/compose.jsx:818
#: src/components/compose.jsx:2444
#: src/components/compose.jsx:2917
#: src/components/compose.jsx:3125
#: src/components/compose.jsx:3355
#: src/components/compose.jsx:859
#: src/components/compose.jsx:2547
#: src/components/compose.jsx:3020
#: src/components/compose.jsx:3228
#: src/components/compose.jsx:3458
#: src/components/drafts.jsx:58
#: src/components/embed-modal.jsx:12
#: src/components/generic-accounts.jsx:142
@ -418,13 +418,13 @@ msgstr ""
#: src/components/shortcuts-settings.jsx:783
#: src/components/status.jsx:2992
#: src/components/status.jsx:3231
#: src/components/status.jsx:3729
#: src/components/status.jsx:3731
#: src/pages/accounts.jsx:36
#: src/pages/catchup.jsx:1581
#: src/pages/filters.jsx:224
#: src/pages/list.jsx:274
#: src/pages/notifications.jsx:868
#: src/pages/notifications.jsx:1082
#: src/pages/notifications.jsx:915
#: src/pages/notifications.jsx:1129
#: src/pages/settings.jsx:77
#: src/pages/status.jsx:1299
msgid "Close"
@ -503,7 +503,7 @@ msgstr ""
#: src/components/list-add-edit.jsx:149
#: src/components/shortcuts-settings.jsx:715
#: src/pages/filters.jsx:554
#: src/pages/notifications.jsx:934
#: src/pages/notifications.jsx:981
msgid "Save"
msgstr ""
@ -531,7 +531,7 @@ msgstr ""
#: src/pages/filters.jsx:89
#: src/pages/followed-hashtags.jsx:40
#: src/pages/home.jsx:53
#: src/pages/notifications.jsx:520
#: src/pages/notifications.jsx:560
msgid "Home"
msgstr ""
@ -540,139 +540,154 @@ msgstr ""
msgid "Compose"
msgstr ""
#: src/components/compose.jsx:394
#: src/components/compose.jsx:206
msgid "Add media"
msgstr "Add media"
#: src/components/compose.jsx:207
msgid "Add custom emoji"
msgstr ""
#: src/components/compose.jsx:208
msgid "Add GIF"
msgstr "Add GIF"
#: src/components/compose.jsx:209
msgid "Add poll"
msgstr ""
#: src/components/compose.jsx:402
msgid "You have unsaved changes. Discard this post?"
msgstr ""
#: src/components/compose.jsx:622
#: src/components/compose.jsx:630
msgid "{0, plural, one {File {1} is not supported.} other {Files {2} are not supported.}}"
msgstr "{0, plural, one {File {1} is not supported.} other {Files {2} are not supported.}}"
#: src/components/compose.jsx:632
#: src/components/compose.jsx:650
#: src/components/compose.jsx:1361
#: src/components/compose.jsx:1623
#: src/components/compose.jsx:640
#: src/components/compose.jsx:658
#: src/components/compose.jsx:1674
#: src/components/compose.jsx:1760
msgid "{maxMediaAttachments, plural, one {You can only attach up to 1 file.} other {You can only attach up to # files.}}"
msgstr ""
#: src/components/compose.jsx:799
#: src/components/compose.jsx:840
msgid "Pop out"
msgstr ""
#: src/components/compose.jsx:806
#: src/components/compose.jsx:847
msgid "Minimize"
msgstr ""
#: src/components/compose.jsx:842
#: src/components/compose.jsx:883
msgid "Looks like you closed the parent window."
msgstr ""
#: src/components/compose.jsx:849
#: src/components/compose.jsx:890
msgid "Looks like you already have a compose field open in the parent window and currently publishing. Please wait for it to be done and try again later."
msgstr ""
#: src/components/compose.jsx:854
#: src/components/compose.jsx:895
msgid "Looks like you already have a compose field open in the parent window. Popping in this window will discard the changes you made in the parent window. Continue?"
msgstr ""
#: src/components/compose.jsx:896
#: src/components/compose.jsx:937
msgid "Pop in"
msgstr ""
#: src/components/compose.jsx:906
#: src/components/compose.jsx:947
msgid "Replying to @{0}s post (<0>{1}</0>)"
msgstr ""
#: src/components/compose.jsx:916
#: src/components/compose.jsx:957
msgid "Replying to @{0}s post"
msgstr ""
#: src/components/compose.jsx:929
#: src/components/compose.jsx:970
msgid "Editing source post"
msgstr ""
#: src/components/compose.jsx:976
#: src/components/compose.jsx:1017
msgid "Poll must have at least 2 options"
msgstr ""
#: src/components/compose.jsx:980
#: src/components/compose.jsx:1021
msgid "Some poll choices are empty"
msgstr ""
#: src/components/compose.jsx:993
#: src/components/compose.jsx:1034
msgid "Some media have no descriptions. Continue?"
msgstr ""
#: src/components/compose.jsx:1045
#: src/components/compose.jsx:1086
msgid "Attachment #{i} failed"
msgstr ""
#: src/components/compose.jsx:1139
#: src/components/compose.jsx:1180
#: src/components/status.jsx:2063
#: src/components/timeline.jsx:984
msgid "Content warning"
msgstr ""
#: src/components/compose.jsx:1155
#: src/components/compose.jsx:1196
msgid "Content warning or sensitive media"
msgstr ""
#: src/components/compose.jsx:1191
#: src/components/compose.jsx:1232
#: src/components/status.jsx:93
#: src/pages/settings.jsx:305
msgid "Public"
msgstr ""
#: src/components/compose.jsx:1196
#: src/components/compose.jsx:1237
#: src/components/nav-menu.jsx:337
#: src/components/shortcuts-settings.jsx:165
#: src/components/status.jsx:94
msgid "Local"
msgstr ""
#: src/components/compose.jsx:1200
#: src/components/compose.jsx:1241
#: src/components/status.jsx:95
#: src/pages/settings.jsx:308
msgid "Unlisted"
msgstr ""
#: src/components/compose.jsx:1203
#: src/components/compose.jsx:1244
#: src/components/status.jsx:96
#: src/pages/settings.jsx:311
msgid "Followers only"
msgstr ""
#: src/components/compose.jsx:1206
#: src/components/compose.jsx:1247
#: src/components/status.jsx:97
#: src/components/status.jsx:1941
msgid "Private mention"
msgstr ""
#: src/components/compose.jsx:1215
#: src/components/compose.jsx:1256
msgid "Post your reply"
msgstr ""
#: src/components/compose.jsx:1217
#: src/components/compose.jsx:1258
msgid "Edit your post"
msgstr ""
#: src/components/compose.jsx:1218
#: src/components/compose.jsx:1259
msgid "What are you doing?"
msgstr ""
#: src/components/compose.jsx:1296
#: src/components/compose.jsx:1337
msgid "Mark media as sensitive"
msgstr ""
#: src/components/compose.jsx:1397
msgid "Add poll"
#: src/components/compose.jsx:1381
#: src/components/compose.jsx:3078
#: src/components/shortcuts-settings.jsx:715
#: src/pages/list.jsx:359
msgid "Add"
msgstr ""
#: src/components/compose.jsx:1419
msgid "Add custom emoji"
msgstr ""
#: src/components/compose.jsx:1504
#: src/components/compose.jsx:1555
#: src/components/keyboard-shortcuts-help.jsx:151
#: src/components/status.jsx:929
#: src/components/status.jsx:1717
@ -681,195 +696,189 @@ msgstr ""
msgid "Reply"
msgstr ""
#: src/components/compose.jsx:1506
#: src/components/compose.jsx:1557
msgid "Update"
msgstr ""
#: src/components/compose.jsx:1507
#: src/components/compose.jsx:1558
msgctxt "Submit button in composer"
msgid "Post"
msgstr ""
#: src/components/compose.jsx:1635
#: src/components/compose.jsx:1686
msgid "Downloading GIF…"
msgstr ""
#: src/components/compose.jsx:1663
#: src/components/compose.jsx:1714
msgid "Failed to download GIF"
msgstr ""
#: src/components/compose.jsx:1775
#: src/components/compose.jsx:1852
#: src/components/compose.jsx:1878
#: src/components/compose.jsx:1955
#: src/components/nav-menu.jsx:238
msgid "More…"
msgstr ""
#: src/components/compose.jsx:2257
#: src/components/compose.jsx:2360
msgid "Uploaded"
msgstr ""
#: src/components/compose.jsx:2270
#: src/components/compose.jsx:2373
msgid "Image description"
msgstr ""
#: src/components/compose.jsx:2271
#: src/components/compose.jsx:2374
msgid "Video description"
msgstr ""
#: src/components/compose.jsx:2272
#: src/components/compose.jsx:2375
msgid "Audio description"
msgstr ""
#: src/components/compose.jsx:2308
#: src/components/compose.jsx:2328
#: src/components/compose.jsx:2411
#: src/components/compose.jsx:2431
msgid "File size too large. Uploading might encounter issues. Try reduce the file size from {0} to {1} or lower."
msgstr ""
#: src/components/compose.jsx:2320
#: src/components/compose.jsx:2340
#: src/components/compose.jsx:2423
#: src/components/compose.jsx:2443
msgid "Dimension too large. Uploading might encounter issues. Try reduce dimension from {0}×{1}px to {2}×{3}px."
msgstr ""
#: src/components/compose.jsx:2348
#: src/components/compose.jsx:2451
msgid "Frame rate too high. Uploading might encounter issues."
msgstr ""
#: src/components/compose.jsx:2408
#: src/components/compose.jsx:2658
#: src/components/compose.jsx:2511
#: src/components/compose.jsx:2761
#: src/components/shortcuts-settings.jsx:726
#: src/pages/catchup.jsx:1074
#: src/pages/filters.jsx:412
msgid "Remove"
msgstr ""
#: src/components/compose.jsx:2425
#: src/components/compose.jsx:2528
#: src/compose.jsx:83
msgid "Error"
msgstr ""
#: src/components/compose.jsx:2450
#: src/components/compose.jsx:2553
msgid "Edit image description"
msgstr ""
#: src/components/compose.jsx:2451
#: src/components/compose.jsx:2554
msgid "Edit video description"
msgstr ""
#: src/components/compose.jsx:2452
#: src/components/compose.jsx:2555
msgid "Edit audio description"
msgstr ""
#: src/components/compose.jsx:2497
#: src/components/compose.jsx:2546
#: src/components/compose.jsx:2600
#: src/components/compose.jsx:2649
msgid "Generating description. Please wait…"
msgstr ""
#: src/components/compose.jsx:2517
#: src/components/compose.jsx:2620
msgid "Failed to generate description: {0}"
msgstr ""
#: src/components/compose.jsx:2518
#: src/components/compose.jsx:2621
msgid "Failed to generate description"
msgstr ""
#: src/components/compose.jsx:2530
#: src/components/compose.jsx:2536
#: src/components/compose.jsx:2582
#: src/components/compose.jsx:2633
#: src/components/compose.jsx:2639
#: src/components/compose.jsx:2685
msgid "Generate description…"
msgstr ""
#: src/components/compose.jsx:2569
#: src/components/compose.jsx:2672
msgid "Failed to generate description{0}"
msgstr ""
#: src/components/compose.jsx:2584
#: src/components/compose.jsx:2687
msgid "({0}) <0>— experimental</0>"
msgstr ""
#: src/components/compose.jsx:2603
#: src/components/compose.jsx:2706
msgid "Done"
msgstr ""
#: src/components/compose.jsx:2639
#: src/components/compose.jsx:2742
msgid "Choice {0}"
msgstr ""
#: src/components/compose.jsx:2686
#: src/components/compose.jsx:2789
msgid "Multiple choices"
msgstr ""
#: src/components/compose.jsx:2689
#: src/components/compose.jsx:2792
msgid "Duration"
msgstr ""
#: src/components/compose.jsx:2720
#: src/components/compose.jsx:2823
msgid "Remove poll"
msgstr ""
#: src/components/compose.jsx:2934
#: src/components/compose.jsx:3037
msgid "Search accounts"
msgstr ""
#: src/components/compose.jsx:2975
#: src/components/shortcuts-settings.jsx:715
#: src/pages/list.jsx:359
msgid "Add"
msgstr ""
#: src/components/compose.jsx:2988
#: src/components/compose.jsx:3091
#: src/components/generic-accounts.jsx:227
msgid "Error loading accounts"
msgstr ""
#: src/components/compose.jsx:3131
#: src/components/compose.jsx:3234
msgid "Custom emojis"
msgstr ""
#: src/components/compose.jsx:3151
#: src/components/compose.jsx:3254
msgid "Search emoji"
msgstr ""
#: src/components/compose.jsx:3182
#: src/components/compose.jsx:3285
msgid "Error loading custom emojis"
msgstr ""
#: src/components/compose.jsx:3193
#: src/components/compose.jsx:3296
msgid "Recently used"
msgstr ""
#: src/components/compose.jsx:3194
#: src/components/compose.jsx:3297
msgid "Others"
msgstr ""
#: src/components/compose.jsx:3232
#: src/components/compose.jsx:3335
msgid "{0} more…"
msgstr ""
#: src/components/compose.jsx:3370
#: src/components/compose.jsx:3473
msgid "Search GIFs"
msgstr ""
#: src/components/compose.jsx:3385
#: src/components/compose.jsx:3488
msgid "Powered by GIPHY"
msgstr ""
#: src/components/compose.jsx:3393
#: src/components/compose.jsx:3496
msgid "Type to search GIFs"
msgstr ""
#: src/components/compose.jsx:3491
#: src/components/compose.jsx:3594
#: src/components/media-modal.jsx:461
#: src/components/timeline.jsx:889
msgid "Previous"
msgstr ""
#: src/components/compose.jsx:3509
#: src/components/compose.jsx:3612
#: src/components/media-modal.jsx:480
#: src/components/timeline.jsx:906
msgid "Next"
msgstr ""
#: src/components/compose.jsx:3526
#: src/components/compose.jsx:3629
msgid "Error loading GIFs"
msgstr ""
@ -932,7 +941,7 @@ msgid "Open in new window"
msgstr ""
#: src/components/follow-request-buttons.jsx:42
#: src/pages/notifications.jsx:918
#: src/pages/notifications.jsx:965
msgid "Accept"
msgstr ""
@ -941,7 +950,7 @@ msgid "Reject"
msgstr ""
#: src/components/follow-request-buttons.jsx:75
#: src/pages/notifications.jsx:1201
#: src/pages/notifications.jsx:1248
msgid "Accepted"
msgstr ""
@ -954,7 +963,7 @@ msgid "Nothing to show"
msgstr ""
#: src/components/generic-accounts.jsx:145
#: src/components/notification.jsx:438
#: src/components/notification.jsx:445
#: src/pages/accounts.jsx:41
#: src/pages/search.jsx:317
#: src/pages/search.jsx:350
@ -964,7 +973,7 @@ msgstr ""
#: src/components/generic-accounts.jsx:205
#: src/components/timeline.jsx:519
#: src/pages/list.jsx:293
#: src/pages/notifications.jsx:848
#: src/pages/notifications.jsx:895
#: src/pages/search.jsx:544
#: src/pages/status.jsx:1332
msgid "Show more…"
@ -1101,7 +1110,7 @@ msgstr ""
#: src/components/keyboard-shortcuts-help.jsx:172
#: src/components/status.jsx:937
#: src/components/status.jsx:2412
#: src/components/status.jsx:2413
#: src/components/status.jsx:2444
#: src/components/status.jsx:2445
msgid "Boost"
@ -1218,9 +1227,9 @@ msgid "Filtered: {filterTitleStr}"
msgstr ""
#: src/components/media-post.jsx:133
#: src/components/status.jsx:3559
#: src/components/status.jsx:3655
#: src/components/status.jsx:3733
#: src/components/status.jsx:3561
#: src/components/status.jsx:3657
#: src/components/status.jsx:3735
#: src/components/timeline.jsx:973
#: src/pages/catchup.jsx:75
#: src/pages/catchup.jsx:1876
@ -1281,8 +1290,8 @@ msgstr ""
#: src/pages/filters.jsx:24
#: src/pages/home.jsx:84
#: src/pages/home.jsx:184
#: src/pages/notifications.jsx:112
#: src/pages/notifications.jsx:524
#: src/pages/notifications.jsx:113
#: src/pages/notifications.jsx:564
msgid "Notifications"
msgstr ""
@ -1403,134 +1412,142 @@ msgstr ""
msgid "View all notifications"
msgstr ""
#: src/components/notification.jsx:70
#: src/components/notification.jsx:71
msgid "{account} reacted to your post with {emojiObject}"
msgstr ""
#: src/components/notification.jsx:77
#: src/components/notification.jsx:78
msgid "{account} published a post."
msgstr ""
#: src/components/notification.jsx:85
#: src/components/notification.jsx:86
msgid "{count, plural, =1 {{postsCount, plural, =1 {{postType, select, reply {{account} boosted your reply.} other {{account} boosted your post.}}} other {{account} boosted {postsCount} of your posts.}}} other {{postType, select, reply {<0><1>{0}</1> people</0> boosted your reply.} other {<2><3>{1}</3> people</2> boosted your post.}}}}"
msgstr ""
#: src/components/notification.jsx:128
#: src/components/notification.jsx:129
msgid "{count, plural, =1 {{account} followed you.} other {<0><1>{0}</1> people</0> followed you.}}"
msgstr ""
#: src/components/notification.jsx:142
#: src/components/notification.jsx:143
msgid "{account} requested to follow you."
msgstr ""
#: src/components/notification.jsx:151
#: src/components/notification.jsx:152
msgid "{count, plural, =1 {{postsCount, plural, =1 {{postType, select, reply {{account} liked your reply.} other {{account} liked your post.}}} other {{account} liked {postsCount} of your posts.}}} other {{postType, select, reply {<0><1>{0}</1> people</0> liked your reply.} other {<2><3>{1}</3> people</2> liked your post.}}}}"
msgstr ""
#: src/components/notification.jsx:193
#: src/components/notification.jsx:194
msgid "A poll you have voted in or created has ended."
msgstr ""
#: src/components/notification.jsx:194
#: src/components/notification.jsx:195
msgid "A poll you have created has ended."
msgstr ""
#: src/components/notification.jsx:195
#: src/components/notification.jsx:196
msgid "A poll you have voted in has ended."
msgstr ""
#: src/components/notification.jsx:196
#: src/components/notification.jsx:197
msgid "A post you interacted with has been edited."
msgstr ""
#: src/components/notification.jsx:204
#: src/components/notification.jsx:205
msgid "{count, plural, =1 {{postsCount, plural, =1 {{postType, select, reply {{account} boosted & liked your reply.} other {{account} boosted & liked your post.}}} other {{account} boosted & liked {postsCount} of your posts.}}} other {{postType, select, reply {<0><1>{0}</1> people</0> boosted & liked your reply.} other {<2><3>{1}</3> people</2> boosted & liked your post.}}}}"
msgstr ""
#: src/components/notification.jsx:246
#: src/components/notification.jsx:247
msgid "{account} signed up."
msgstr ""
#: src/components/notification.jsx:248
#: src/components/notification.jsx:249
msgid "{account} reported {targetAccount}"
msgstr ""
#: src/components/notification.jsx:253
#: src/components/notification.jsx:254
msgid "Lost connections with <0>{name}</0>."
msgstr ""
#: src/components/notification.jsx:259
#: src/components/notification.jsx:260
msgid "Moderation warning"
msgstr ""
#: src/components/notification.jsx:269
#: src/components/notification.jsx:265
msgid "Your {year} #Wrapstodon is here!"
msgstr "Your {year} #Wrapstodon is here!"
#: src/components/notification.jsx:271
msgid "An admin from <0>{from}</0> has suspended <1>{targetName}</1>, which means you can no longer receive updates from them or interact with them."
msgstr ""
#: src/components/notification.jsx:275
#: src/components/notification.jsx:277
msgid "An admin from <0>{from}</0> has blocked <1>{targetName}</1>. Affected followers: {followersCount}, followings: {followingCount}."
msgstr ""
#: src/components/notification.jsx:281
#: src/components/notification.jsx:283
msgid "You have blocked <0>{targetName}</0>. Removed followers: {followersCount}, followings: {followingCount}."
msgstr ""
#: src/components/notification.jsx:289
#: src/components/notification.jsx:291
msgid "Your account has received a moderation warning."
msgstr ""
#: src/components/notification.jsx:290
#: src/components/notification.jsx:292
msgid "Your account has been disabled."
msgstr ""
#: src/components/notification.jsx:291
#: src/components/notification.jsx:293
msgid "Some of your posts have been marked as sensitive."
msgstr ""
#: src/components/notification.jsx:292
#: src/components/notification.jsx:294
msgid "Some of your posts have been deleted."
msgstr ""
#: src/components/notification.jsx:293
#: src/components/notification.jsx:295
msgid "Your posts will be marked as sensitive from now on."
msgstr ""
#: src/components/notification.jsx:294
#: src/components/notification.jsx:296
msgid "Your account has been limited."
msgstr ""
#: src/components/notification.jsx:295
#: src/components/notification.jsx:297
msgid "Your account has been suspended."
msgstr ""
#: src/components/notification.jsx:369
#: src/components/notification.jsx:372
msgid "[Unknown notification type: {type}]"
msgstr ""
#: src/components/notification.jsx:434
#: src/components/notification.jsx:441
#: src/components/status.jsx:1036
#: src/components/status.jsx:1046
msgid "Boosted/Liked by…"
msgstr ""
#: src/components/notification.jsx:435
#: src/components/notification.jsx:442
msgid "Liked by…"
msgstr ""
#: src/components/notification.jsx:436
#: src/components/notification.jsx:443
msgid "Boosted by…"
msgstr ""
#: src/components/notification.jsx:437
#: src/components/notification.jsx:444
msgid "Followed by…"
msgstr ""
#: src/components/notification.jsx:508
#: src/components/notification.jsx:524
#: src/components/notification.jsx:515
#: src/components/notification.jsx:531
msgid "Learn more <0/>"
msgstr ""
#: src/components/notification.jsx:756
#: src/components/notification.jsx:540
msgid "View #Wrapstodon"
msgstr "View #Wrapstodon"
#: src/components/notification.jsx:770
#: src/components/status.jsx:267
msgid "Read more →"
msgstr ""
@ -2048,18 +2065,18 @@ msgstr ""
#: src/components/status.jsx:937
#: src/components/status.jsx:999
#: src/components/status.jsx:2412
#: src/components/status.jsx:2413
#: src/components/status.jsx:2444
msgid "Unboost"
msgstr ""
#: src/components/status.jsx:953
#: src/components/status.jsx:2427
#: src/components/status.jsx:2428
msgid "Quote"
msgstr ""
#: src/components/status.jsx:961
#: src/components/status.jsx:2436
#: src/components/status.jsx:2437
msgid "Some media have no descriptions."
msgstr ""
@ -2251,6 +2268,7 @@ msgid "Failed to load history"
msgstr ""
#: src/components/status.jsx:3006
#: src/pages/annual-report.jsx:46
msgid "Loading…"
msgstr ""
@ -2312,7 +2330,7 @@ msgid "Note: This preview is lightly styled."
msgstr ""
#. [Name] [Visibility icon] boosted
#: src/components/status.jsx:3663
#: src/components/status.jsx:3665
msgid "<0/> <1/> boosted"
msgstr ""
@ -2323,7 +2341,7 @@ msgstr ""
#: src/components/timeline.jsx:554
#: src/pages/home.jsx:213
#: src/pages/notifications.jsx:824
#: src/pages/notifications.jsx:871
#: src/pages/status.jsx:988
#: src/pages/status.jsx:1361
msgid "Try again"
@ -2392,6 +2410,7 @@ msgid "Login required."
msgstr "Login required."
#: src/compose.jsx:90
#: src/pages/annual-report.jsx:165
#: src/pages/http-route.jsx:91
#: src/pages/login.jsx:270
msgid "Go home"
@ -3135,125 +3154,125 @@ msgstr ""
msgid "Unable to load mentions."
msgstr ""
#: src/pages/notifications.jsx:103
#: src/pages/notifications.jsx:104
msgid "You don't follow"
msgstr ""
#: src/pages/notifications.jsx:104
#: src/pages/notifications.jsx:105
msgid "Who don't follow you"
msgstr ""
#: src/pages/notifications.jsx:105
#: src/pages/notifications.jsx:106
msgid "With a new account"
msgstr ""
#: src/pages/notifications.jsx:106
#: src/pages/notifications.jsx:107
msgid "Who unsolicitedly private mention you"
msgstr ""
#: src/pages/notifications.jsx:107
#: src/pages/notifications.jsx:108
msgid "Who are limited by server moderators"
msgstr ""
#: src/pages/notifications.jsx:538
#: src/pages/notifications.jsx:872
#: src/pages/notifications.jsx:578
#: src/pages/notifications.jsx:919
msgid "Notifications settings"
msgstr ""
#: src/pages/notifications.jsx:556
#: src/pages/notifications.jsx:596
msgid "New notifications"
msgstr ""
#: src/pages/notifications.jsx:567
#: src/pages/notifications.jsx:607
msgid "{0, plural, one {Announcement} other {Announcements}}"
msgstr ""
#: src/pages/notifications.jsx:614
#: src/pages/notifications.jsx:654
#: src/pages/settings.jsx:1161
msgid "Follow requests"
msgstr ""
#: src/pages/notifications.jsx:619
#: src/pages/notifications.jsx:659
msgid "{0, plural, one {# follow request} other {# follow requests}}"
msgstr ""
#: src/pages/notifications.jsx:674
#: src/pages/notifications.jsx:714
msgid "{0, plural, one {Filtered notifications from # person} other {Filtered notifications from # people}}"
msgstr ""
#: src/pages/notifications.jsx:740
#: src/pages/notifications.jsx:787
msgid "Only mentions"
msgstr ""
#: src/pages/notifications.jsx:744
#: src/pages/notifications.jsx:791
msgid "Today"
msgstr ""
#: src/pages/notifications.jsx:749
#: src/pages/notifications.jsx:796
msgid "You're all caught up."
msgstr ""
#: src/pages/notifications.jsx:772
#: src/pages/notifications.jsx:819
msgid "Yesterday"
msgstr ""
#: src/pages/notifications.jsx:820
#: src/pages/notifications.jsx:867
msgid "Unable to load notifications"
msgstr ""
#: src/pages/notifications.jsx:899
#: src/pages/notifications.jsx:946
msgid "Notifications settings updated"
msgstr ""
#: src/pages/notifications.jsx:907
#: src/pages/notifications.jsx:954
msgid "Filter out notifications from people:"
msgstr ""
#: src/pages/notifications.jsx:921
#: src/pages/notifications.jsx:968
msgid "Filter"
msgstr ""
#: src/pages/notifications.jsx:924
#: src/pages/notifications.jsx:971
msgid "Ignore"
msgstr ""
#: src/pages/notifications.jsx:997
#: src/pages/notifications.jsx:1044
msgid "Updated <0>{0}</0>"
msgstr ""
#: src/pages/notifications.jsx:1065
#: src/pages/notifications.jsx:1112
msgid "View notifications from <0>@{0}</0>"
msgstr ""
#: src/pages/notifications.jsx:1086
#: src/pages/notifications.jsx:1133
msgid "Notifications from <0>@{0}</0>"
msgstr ""
#: src/pages/notifications.jsx:1153
#: src/pages/notifications.jsx:1200
msgid "Notifications from @{0} will not be filtered from now on."
msgstr ""
#: src/pages/notifications.jsx:1158
#: src/pages/notifications.jsx:1205
msgid "Unable to accept notification request"
msgstr ""
#: src/pages/notifications.jsx:1163
#: src/pages/notifications.jsx:1210
msgid "Allow"
msgstr ""
#: src/pages/notifications.jsx:1183
#: src/pages/notifications.jsx:1230
msgid "Notifications from @{0} will not show up in Filtered notifications from now on."
msgstr ""
#: src/pages/notifications.jsx:1188
#: src/pages/notifications.jsx:1235
msgid "Unable to dismiss notification request"
msgstr ""
#: src/pages/notifications.jsx:1193
#: src/pages/notifications.jsx:1240
msgid "Dismiss"
msgstr ""
#: src/pages/notifications.jsx:1208
#: src/pages/notifications.jsx:1255
msgid "Dismissed"
msgstr ""

1287
src/locales/eo-UY.po generated

File diff suppressed because it is too large Load diff

681
src/locales/es-ES.po generated

File diff suppressed because it is too large Load diff

1173
src/locales/eu-ES.po generated

File diff suppressed because it is too large Load diff

1179
src/locales/fa-IR.po generated

File diff suppressed because it is too large Load diff

1173
src/locales/fi-FI.po generated

File diff suppressed because it is too large Load diff

1175
src/locales/fr-FR.po generated

File diff suppressed because it is too large Load diff

1191
src/locales/gl-ES.po generated

File diff suppressed because it is too large Load diff

1173
src/locales/he-IL.po generated

File diff suppressed because it is too large Load diff

1191
src/locales/it-IT.po generated

File diff suppressed because it is too large Load diff

1173
src/locales/ja-JP.po generated

File diff suppressed because it is too large Load diff

1173
src/locales/kab.po generated

File diff suppressed because it is too large Load diff

1079
src/locales/ko-KR.po generated

File diff suppressed because it is too large Load diff

569
src/locales/lt-LT.po generated

File diff suppressed because it is too large Load diff

275
src/locales/nb-NO.po generated
View file

@ -8,7 +8,7 @@ msgstr ""
"Language: nb_NO\n"
"Project-Id-Version: phanpy\n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: 2024-11-21 12:34\n"
"PO-Revision-Date: 2024-12-03 18:15\n"
"Last-Translator: \n"
"Language-Team: Norwegian Bokmal\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
@ -109,7 +109,7 @@ msgstr "Innlegg"
#: src/components/account-info.jsx:429
#: src/components/account-info.jsx:1120
#: src/components/compose.jsx:2488
#: src/components/compose.jsx:2591
#: src/components/media-alt-modal.jsx:45
#: src/components/media-modal.jsx:357
#: src/components/status.jsx:1737
@ -404,11 +404,11 @@ msgstr "Følg"
#: src/components/account-info.jsx:1994
#: src/components/account-info.jsx:2094
#: src/components/account-sheet.jsx:37
#: src/components/compose.jsx:818
#: src/components/compose.jsx:2444
#: src/components/compose.jsx:2917
#: src/components/compose.jsx:3125
#: src/components/compose.jsx:3355
#: src/components/compose.jsx:859
#: src/components/compose.jsx:2547
#: src/components/compose.jsx:3020
#: src/components/compose.jsx:3228
#: src/components/compose.jsx:3458
#: src/components/drafts.jsx:58
#: src/components/embed-modal.jsx:12
#: src/components/generic-accounts.jsx:142
@ -423,7 +423,7 @@ msgstr "Følg"
#: src/components/shortcuts-settings.jsx:783
#: src/components/status.jsx:2992
#: src/components/status.jsx:3231
#: src/components/status.jsx:3729
#: src/components/status.jsx:3731
#: src/pages/accounts.jsx:36
#: src/pages/catchup.jsx:1581
#: src/pages/filters.jsx:224
@ -545,139 +545,154 @@ msgstr "Hjem"
msgid "Compose"
msgstr "Skriv ny"
#: src/components/compose.jsx:394
#: src/components/compose.jsx:206
msgid "Add media"
msgstr ""
#: src/components/compose.jsx:207
msgid "Add custom emoji"
msgstr "Legg til egendefinert emoji"
#: src/components/compose.jsx:208
msgid "Add GIF"
msgstr ""
#: src/components/compose.jsx:209
msgid "Add poll"
msgstr "Legg til avstemming"
#: src/components/compose.jsx:402
msgid "You have unsaved changes. Discard this post?"
msgstr "Du har ulagrede endringer. Forkast dette innlegget?"
#: src/components/compose.jsx:622
#: src/components/compose.jsx:630
msgid "{0, plural, one {File {1} is not supported.} other {Files {2} are not supported.}}"
msgstr ""
#: src/components/compose.jsx:632
#: src/components/compose.jsx:650
#: src/components/compose.jsx:1361
#: src/components/compose.jsx:1623
#: src/components/compose.jsx:640
#: src/components/compose.jsx:658
#: src/components/compose.jsx:1674
#: src/components/compose.jsx:1760
msgid "{maxMediaAttachments, plural, one {You can only attach up to 1 file.} other {You can only attach up to # files.}}"
msgstr ""
#: src/components/compose.jsx:799
#: src/components/compose.jsx:840
msgid "Pop out"
msgstr ""
#: src/components/compose.jsx:806
#: src/components/compose.jsx:847
msgid "Minimize"
msgstr "Minimer"
#: src/components/compose.jsx:842
#: src/components/compose.jsx:883
msgid "Looks like you closed the parent window."
msgstr "Ser ut som du lukket foreldrevinduet."
#: src/components/compose.jsx:849
#: src/components/compose.jsx:890
msgid "Looks like you already have a compose field open in the parent window and currently publishing. Please wait for it to be done and try again later."
msgstr ""
#: src/components/compose.jsx:854
#: src/components/compose.jsx:895
msgid "Looks like you already have a compose field open in the parent window. Popping in this window will discard the changes you made in the parent window. Continue?"
msgstr ""
#: src/components/compose.jsx:896
#: src/components/compose.jsx:937
msgid "Pop in"
msgstr ""
#: src/components/compose.jsx:906
#: src/components/compose.jsx:947
msgid "Replying to @{0}s post (<0>{1}</0>)"
msgstr "Svarer til @{0} sitt innlegg (<0>{1}</0>)"
#: src/components/compose.jsx:916
#: src/components/compose.jsx:957
msgid "Replying to @{0}s post"
msgstr "Svarer på @{0} sitt innlegg"
#: src/components/compose.jsx:929
#: src/components/compose.jsx:970
msgid "Editing source post"
msgstr ""
#: src/components/compose.jsx:976
#: src/components/compose.jsx:1017
msgid "Poll must have at least 2 options"
msgstr "Avstemning må ha minst 2 alternativer"
#: src/components/compose.jsx:980
#: src/components/compose.jsx:1021
msgid "Some poll choices are empty"
msgstr "Noen avstemningsvalg er tomme"
#: src/components/compose.jsx:993
#: src/components/compose.jsx:1034
msgid "Some media have no descriptions. Continue?"
msgstr "Noen media mangler beskrivelser. Fortsett?"
#: src/components/compose.jsx:1045
#: src/components/compose.jsx:1086
msgid "Attachment #{i} failed"
msgstr "Vedlegg #{i} mislyktes"
#: src/components/compose.jsx:1139
#: src/components/compose.jsx:1180
#: src/components/status.jsx:2063
#: src/components/timeline.jsx:984
msgid "Content warning"
msgstr "Innholdsvarsel"
#: src/components/compose.jsx:1155
#: src/components/compose.jsx:1196
msgid "Content warning or sensitive media"
msgstr "Innholdsvarsel eller sensitive media"
#: src/components/compose.jsx:1191
#: src/components/compose.jsx:1232
#: src/components/status.jsx:93
#: src/pages/settings.jsx:305
msgid "Public"
msgstr "Offentlig"
#: src/components/compose.jsx:1196
#: src/components/compose.jsx:1237
#: src/components/nav-menu.jsx:337
#: src/components/shortcuts-settings.jsx:165
#: src/components/status.jsx:94
msgid "Local"
msgstr "Lokal"
#: src/components/compose.jsx:1200
#: src/components/compose.jsx:1241
#: src/components/status.jsx:95
#: src/pages/settings.jsx:308
msgid "Unlisted"
msgstr "Ikke listet"
#: src/components/compose.jsx:1203
#: src/components/compose.jsx:1244
#: src/components/status.jsx:96
#: src/pages/settings.jsx:311
msgid "Followers only"
msgstr "Kun følgere"
#: src/components/compose.jsx:1206
#: src/components/compose.jsx:1247
#: src/components/status.jsx:97
#: src/components/status.jsx:1941
msgid "Private mention"
msgstr "Privat omtale"
#: src/components/compose.jsx:1215
#: src/components/compose.jsx:1256
msgid "Post your reply"
msgstr "Skriv ditt svar"
#: src/components/compose.jsx:1217
#: src/components/compose.jsx:1258
msgid "Edit your post"
msgstr "Rediger innlegget ditt"
#: src/components/compose.jsx:1218
#: src/components/compose.jsx:1259
msgid "What are you doing?"
msgstr "Hva gjør du?"
#: src/components/compose.jsx:1296
#: src/components/compose.jsx:1337
msgid "Mark media as sensitive"
msgstr "Marker media som sensitivt"
#: src/components/compose.jsx:1397
msgid "Add poll"
msgstr "Legg til avstemming"
#: src/components/compose.jsx:1381
#: src/components/compose.jsx:3078
#: src/components/shortcuts-settings.jsx:715
#: src/pages/list.jsx:359
msgid "Add"
msgstr "Legg til"
#: src/components/compose.jsx:1419
msgid "Add custom emoji"
msgstr "Legg til egendefinert emoji"
#: src/components/compose.jsx:1504
#: src/components/compose.jsx:1555
#: src/components/keyboard-shortcuts-help.jsx:151
#: src/components/status.jsx:929
#: src/components/status.jsx:1717
@ -686,195 +701,189 @@ msgstr "Legg til egendefinert emoji"
msgid "Reply"
msgstr "Svar"
#: src/components/compose.jsx:1506
#: src/components/compose.jsx:1557
msgid "Update"
msgstr "Oppdater"
#: src/components/compose.jsx:1507
#: src/components/compose.jsx:1558
msgctxt "Submit button in composer"
msgid "Post"
msgstr "Publiser"
#: src/components/compose.jsx:1635
#: src/components/compose.jsx:1686
msgid "Downloading GIF…"
msgstr "Laster ned GIF…"
#: src/components/compose.jsx:1663
#: src/components/compose.jsx:1714
msgid "Failed to download GIF"
msgstr "Kunne ikke laste ned GIF"
#: src/components/compose.jsx:1775
#: src/components/compose.jsx:1852
#: src/components/compose.jsx:1878
#: src/components/compose.jsx:1955
#: src/components/nav-menu.jsx:238
msgid "More…"
msgstr "Mer…"
#: src/components/compose.jsx:2257
#: src/components/compose.jsx:2360
msgid "Uploaded"
msgstr "Lastet opp"
#: src/components/compose.jsx:2270
#: src/components/compose.jsx:2373
msgid "Image description"
msgstr "Bildebeskrivelse"
#: src/components/compose.jsx:2271
#: src/components/compose.jsx:2374
msgid "Video description"
msgstr "Videobeskrivelse"
#: src/components/compose.jsx:2272
#: src/components/compose.jsx:2375
msgid "Audio description"
msgstr "Lydbeskrivelse"
#: src/components/compose.jsx:2308
#: src/components/compose.jsx:2328
#: src/components/compose.jsx:2411
#: src/components/compose.jsx:2431
msgid "File size too large. Uploading might encounter issues. Try reduce the file size from {0} to {1} or lower."
msgstr ""
#: src/components/compose.jsx:2320
#: src/components/compose.jsx:2340
#: src/components/compose.jsx:2423
#: src/components/compose.jsx:2443
msgid "Dimension too large. Uploading might encounter issues. Try reduce dimension from {0}×{1}px to {2}×{3}px."
msgstr ""
#: src/components/compose.jsx:2348
#: src/components/compose.jsx:2451
msgid "Frame rate too high. Uploading might encounter issues."
msgstr ""
#: src/components/compose.jsx:2408
#: src/components/compose.jsx:2658
#: src/components/compose.jsx:2511
#: src/components/compose.jsx:2761
#: src/components/shortcuts-settings.jsx:726
#: src/pages/catchup.jsx:1074
#: src/pages/filters.jsx:412
msgid "Remove"
msgstr "Fjern"
#: src/components/compose.jsx:2425
#: src/components/compose.jsx:2528
#: src/compose.jsx:83
msgid "Error"
msgstr "Feil"
#: src/components/compose.jsx:2450
#: src/components/compose.jsx:2553
msgid "Edit image description"
msgstr "Rediger bildebeskrivelse"
#: src/components/compose.jsx:2451
#: src/components/compose.jsx:2554
msgid "Edit video description"
msgstr "Rediger videobeskrivelse"
#: src/components/compose.jsx:2452
#: src/components/compose.jsx:2555
msgid "Edit audio description"
msgstr "Rediger lydbeskrivelse"
#: src/components/compose.jsx:2497
#: src/components/compose.jsx:2546
#: src/components/compose.jsx:2600
#: src/components/compose.jsx:2649
msgid "Generating description. Please wait…"
msgstr "Genererer beskrivelse. Vennligst vent…"
#: src/components/compose.jsx:2517
#: src/components/compose.jsx:2620
msgid "Failed to generate description: {0}"
msgstr "Kunne ikke generere beskrivelse: {0}"
#: src/components/compose.jsx:2518
#: src/components/compose.jsx:2621
msgid "Failed to generate description"
msgstr "Kunne ikke generere beskrivelse"
#: src/components/compose.jsx:2530
#: src/components/compose.jsx:2536
#: src/components/compose.jsx:2582
#: src/components/compose.jsx:2633
#: src/components/compose.jsx:2639
#: src/components/compose.jsx:2685
msgid "Generate description…"
msgstr "Generer beskrivelse…"
#: src/components/compose.jsx:2569
#: src/components/compose.jsx:2672
msgid "Failed to generate description{0}"
msgstr "Kunne ikke generere beskrivelse{0}"
#: src/components/compose.jsx:2584
#: src/components/compose.jsx:2687
msgid "({0}) <0>— experimental</0>"
msgstr "({0}) <0>— eksperimentell</0>"
#: src/components/compose.jsx:2603
#: src/components/compose.jsx:2706
msgid "Done"
msgstr "Ferdig"
#: src/components/compose.jsx:2639
#: src/components/compose.jsx:2742
msgid "Choice {0}"
msgstr "Valg {0}"
#: src/components/compose.jsx:2686
#: src/components/compose.jsx:2789
msgid "Multiple choices"
msgstr "Flere alternativer"
#: src/components/compose.jsx:2689
#: src/components/compose.jsx:2792
msgid "Duration"
msgstr "Varighet"
#: src/components/compose.jsx:2720
#: src/components/compose.jsx:2823
msgid "Remove poll"
msgstr "Fjern avstemming"
#: src/components/compose.jsx:2934
#: src/components/compose.jsx:3037
msgid "Search accounts"
msgstr "Søk konti"
#: src/components/compose.jsx:2975
#: src/components/shortcuts-settings.jsx:715
#: src/pages/list.jsx:359
msgid "Add"
msgstr "Legg til"
#: src/components/compose.jsx:2988
#: src/components/compose.jsx:3091
#: src/components/generic-accounts.jsx:227
msgid "Error loading accounts"
msgstr "Feil ved lasting av konti"
#: src/components/compose.jsx:3131
#: src/components/compose.jsx:3234
msgid "Custom emojis"
msgstr "Egendefinerte emojier"
#: src/components/compose.jsx:3151
#: src/components/compose.jsx:3254
msgid "Search emoji"
msgstr "Søk emojier"
#: src/components/compose.jsx:3182
#: src/components/compose.jsx:3285
msgid "Error loading custom emojis"
msgstr "Feil ved lasting av egendefinerte emojier"
#: src/components/compose.jsx:3193
#: src/components/compose.jsx:3296
msgid "Recently used"
msgstr "Nylig brukt"
#: src/components/compose.jsx:3194
#: src/components/compose.jsx:3297
msgid "Others"
msgstr "Andre"
#: src/components/compose.jsx:3232
#: src/components/compose.jsx:3335
msgid "{0} more…"
msgstr "{0} fler…"
#: src/components/compose.jsx:3370
#: src/components/compose.jsx:3473
msgid "Search GIFs"
msgstr "Søk GIFer"
#: src/components/compose.jsx:3385
#: src/components/compose.jsx:3488
msgid "Powered by GIPHY"
msgstr "Drevet av GIPHY"
#: src/components/compose.jsx:3393
#: src/components/compose.jsx:3496
msgid "Type to search GIFs"
msgstr "Skriv for å søke GIFer"
#: src/components/compose.jsx:3491
#: src/components/compose.jsx:3594
#: src/components/media-modal.jsx:461
#: src/components/timeline.jsx:889
msgid "Previous"
msgstr "Forrige"
#: src/components/compose.jsx:3509
#: src/components/compose.jsx:3612
#: src/components/media-modal.jsx:480
#: src/components/timeline.jsx:906
msgid "Next"
msgstr "Neste"
#: src/components/compose.jsx:3526
#: src/components/compose.jsx:3629
msgid "Error loading GIFs"
msgstr "Feil ved lasting av GIFer"
@ -959,7 +968,7 @@ msgid "Nothing to show"
msgstr "Ingenting å vise"
#: src/components/generic-accounts.jsx:145
#: src/components/notification.jsx:438
#: src/components/notification.jsx:446
#: src/pages/accounts.jsx:41
#: src/pages/search.jsx:317
#: src/pages/search.jsx:350
@ -1106,7 +1115,7 @@ msgstr ""
#: src/components/keyboard-shortcuts-help.jsx:172
#: src/components/status.jsx:937
#: src/components/status.jsx:2412
#: src/components/status.jsx:2413
#: src/components/status.jsx:2444
#: src/components/status.jsx:2445
msgid "Boost"
@ -1223,9 +1232,9 @@ msgid "Filtered: {filterTitleStr}"
msgstr ""
#: src/components/media-post.jsx:133
#: src/components/status.jsx:3559
#: src/components/status.jsx:3655
#: src/components/status.jsx:3733
#: src/components/status.jsx:3561
#: src/components/status.jsx:3657
#: src/components/status.jsx:3735
#: src/components/timeline.jsx:973
#: src/pages/catchup.jsx:75
#: src/pages/catchup.jsx:1876
@ -1468,74 +1477,82 @@ msgstr ""
msgid "Moderation warning"
msgstr ""
#: src/components/notification.jsx:269
#: src/components/notification.jsx:265
msgid "Your {year} #Wrapstodon is here!"
msgstr ""
#: src/components/notification.jsx:272
msgid "An admin from <0>{from}</0> has suspended <1>{targetName}</1>, which means you can no longer receive updates from them or interact with them."
msgstr ""
#: src/components/notification.jsx:275
#: src/components/notification.jsx:278
msgid "An admin from <0>{from}</0> has blocked <1>{targetName}</1>. Affected followers: {followersCount}, followings: {followingCount}."
msgstr ""
#: src/components/notification.jsx:281
#: src/components/notification.jsx:284
msgid "You have blocked <0>{targetName}</0>. Removed followers: {followersCount}, followings: {followingCount}."
msgstr ""
#: src/components/notification.jsx:289
#: src/components/notification.jsx:292
msgid "Your account has received a moderation warning."
msgstr ""
#: src/components/notification.jsx:290
#: src/components/notification.jsx:293
msgid "Your account has been disabled."
msgstr "Kontoen din har blitt deaktivert."
#: src/components/notification.jsx:291
#: src/components/notification.jsx:294
msgid "Some of your posts have been marked as sensitive."
msgstr ""
#: src/components/notification.jsx:292
#: src/components/notification.jsx:295
msgid "Some of your posts have been deleted."
msgstr "Noen av dine innlegg har blitt slettet."
#: src/components/notification.jsx:293
#: src/components/notification.jsx:296
msgid "Your posts will be marked as sensitive from now on."
msgstr ""
#: src/components/notification.jsx:294
#: src/components/notification.jsx:297
msgid "Your account has been limited."
msgstr ""
#: src/components/notification.jsx:295
#: src/components/notification.jsx:298
msgid "Your account has been suspended."
msgstr ""
#: src/components/notification.jsx:369
#: src/components/notification.jsx:373
msgid "[Unknown notification type: {type}]"
msgstr ""
#: src/components/notification.jsx:434
#: src/components/notification.jsx:442
#: src/components/status.jsx:1036
#: src/components/status.jsx:1046
msgid "Boosted/Liked by…"
msgstr ""
#: src/components/notification.jsx:435
#: src/components/notification.jsx:443
msgid "Liked by…"
msgstr ""
#: src/components/notification.jsx:436
#: src/components/notification.jsx:444
msgid "Boosted by…"
msgstr ""
#: src/components/notification.jsx:437
#: src/components/notification.jsx:445
msgid "Followed by…"
msgstr ""
#: src/components/notification.jsx:508
#: src/components/notification.jsx:524
#: src/components/notification.jsx:516
#: src/components/notification.jsx:532
msgid "Learn more <0/>"
msgstr ""
#: src/components/notification.jsx:756
#: src/components/notification.jsx:540
msgid "View #Wrapstodon"
msgstr ""
#: src/components/notification.jsx:769
#: src/components/status.jsx:267
msgid "Read more →"
msgstr "Les mer →"
@ -2053,18 +2070,18 @@ msgstr "Bokmerket @{0} sitt innlegg"
#: src/components/status.jsx:937
#: src/components/status.jsx:999
#: src/components/status.jsx:2412
#: src/components/status.jsx:2413
#: src/components/status.jsx:2444
msgid "Unboost"
msgstr ""
#: src/components/status.jsx:953
#: src/components/status.jsx:2427
#: src/components/status.jsx:2428
msgid "Quote"
msgstr "Siter"
#: src/components/status.jsx:961
#: src/components/status.jsx:2436
#: src/components/status.jsx:2437
msgid "Some media have no descriptions."
msgstr ""
@ -2256,6 +2273,7 @@ msgid "Failed to load history"
msgstr "Kunne ikke laste inn historikk"
#: src/components/status.jsx:3006
#: src/pages/annual-report.jsx:44
msgid "Loading…"
msgstr "Laster…"
@ -2317,7 +2335,7 @@ msgid "Note: This preview is lightly styled."
msgstr ""
#. [Name] [Visibility icon] boosted
#: src/components/status.jsx:3663
#: src/components/status.jsx:3665
msgid "<0/> <1/> boosted"
msgstr ""
@ -2397,6 +2415,7 @@ msgid "Login required."
msgstr ""
#: src/compose.jsx:90
#: src/pages/annual-report.jsx:132
#: src/pages/http-route.jsx:91
#: src/pages/login.jsx:270
msgid "Go home"

1173
src/locales/nl-NL.po generated

File diff suppressed because it is too large Load diff

1171
src/locales/oc-FR.po generated

File diff suppressed because it is too large Load diff

1171
src/locales/pl-PL.po generated

File diff suppressed because it is too large Load diff

561
src/locales/pt-BR.po generated

File diff suppressed because it is too large Load diff

561
src/locales/pt-PT.po generated

File diff suppressed because it is too large Load diff

1173
src/locales/ru-RU.po generated

File diff suppressed because it is too large Load diff

559
src/locales/th-TH.po generated

File diff suppressed because it is too large Load diff

877
src/locales/uk-UA.po generated

File diff suppressed because it is too large Load diff

561
src/locales/zh-CN.po generated

File diff suppressed because it is too large Load diff

1173
src/locales/zh-TW.po generated

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,85 @@
#annual-report-page {
.report {
background-color: var(--bg-color);
border: 16px ridge var(--bg-faded-color);
box-shadow: 0 0 0 2px var(--bg-color);
padding: 16px;
margin: 80px auto;
max-width: var(--main-width);
font-family: var(--monospace-font);
font-variant-numeric: slashed-zero;
font-feature-settings: 'ss01';
font-variant-numeric: tabular-nums;
min-height: 80vh;
h1 {
margin: 0;
padding: 0;
}
dt {
font-weight: bold;
font-size: larger;
}
dd {
margin: 0 0 2em;
padding: 0;
overflow: auto;
}
table {
width: 100%;
td,
th {
vertical-align: top;
&.number {
text-align: end;
}
}
th {
font-weight: normal;
text-align: start;
color: var(--text-insignificant-color);
text-transform: uppercase;
}
tr > * {
border-top: 1px dashed var(--outline-color);
~ * {
padding-inline-start: 1ch;
}
}
}
.report-topStatuses {
dt {
font-size: var(--text-size);
}
dd {
margin-block-end: 1em;
> a {
display: block;
color: inherit;
text-decoration: none;
border: 2px dashed var(--outline-stronger-color);
&:is(:hover, :focus) {
border-color: var(--text-color);
}
}
.status {
pointer-events: none;
font-size: calc(var(--text-size) * 0.8);
}
}
}
}
}

170
src/pages/annual-report.jsx Normal file
View file

@ -0,0 +1,170 @@
import { t, Trans } from '@lingui/macro';
import './annual-report.css';
import { useEffect, useState } from 'preact/hooks';
import { useParams } from 'react-router-dom';
import Link from '../components/link';
import Loader from '../components/loader';
import NameText from '../components/name-text';
import Status from '../components/status';
import { api } from '../utils/api';
import useTitle from '../utils/useTitle';
export default function AnnualReport() {
const params = useParams();
const { year } = params;
useTitle(year ? `Annual Report: ${year}` : 'Annual Report');
const { masto, instance } = api();
const [results, setResults] = useState(null);
const [uiState, setUIState] = useState('default');
useEffect(() => {
if (year) {
(async () => {
setUIState('loading');
const results = await masto.v1.annualReports.$select(year).fetch();
console.log('REPORT', results);
setResults(results);
setUIState('default');
})();
}
}, [year]);
const { accounts, annualReports, statuses } = results || {};
const report = annualReports?.find((report) => report.year == year)?.data;
const datePlaceholder = new Date();
return (
<div id="annual-report-page" class="deck-container" tabIndex="-1">
<div class="report">
<h1>{year} #Wrapstodon</h1>
{uiState === 'loading' && (
<p>
<Loader abrupt /> <Trans>Loading</Trans>
</p>
)}
{!!report && (
<dl>
{Object.entries(report).map(([key, value]) => (
<>
<dt>{key}</dt>
<dd class={`report-${key}`}>
{Array.isArray(value) ? (
<table>
<thead>
<tr>
{Object.entries(value[0]).map(([key, value]) => (
<th
class={
key !== 'month' && typeof value === 'number'
? 'number'
: ''
}
>
{key}
</th>
))}
</tr>
</thead>
<tbody>
{value.map((item) => (
<tr>
{Object.entries(item).map(([k, value]) => (
<td
class={
k !== 'month' && typeof value === 'number'
? 'number'
: ''
}
>
{value &&
/(accountId)/i.test(k) &&
/^(mostRebloggedAccounts|commonlyInteractedWithAccounts)$/i.test(
key,
) ? (
<NameText
account={accounts?.find(
(a) => a.id === value,
)}
showAvatar
/>
) : k === 'month' ? (
datePlaceholder.setMonth(value - 1) &&
datePlaceholder.toLocaleString(undefined, {
month: 'long',
})
) : typeof value === 'number' ? (
value.toLocaleString()
) : (
value
)}
</td>
))}
</tr>
))}
</tbody>
</table>
) : typeof value === 'object' ? (
/^(topStatuses)$/i.test(key) ? (
<dl>
{Object.entries(value).map(([k, value]) => (
<>
<dt>{k}</dt>
<dd>
{value && (
<Link to={`/${instance}/s/${value}`}>
<Status
status={statuses?.find(
(s) => s.id === value,
)}
size="s"
readOnly
/>
</Link>
)}
</dd>
</>
))}
</dl>
) : (
<table>
<tbody>
{Object.entries(value).map(([k, value]) => (
<tr>
<th>{k}</th>
<td
class={
typeof value === 'number' ? 'number' : ''
}
>
{value}
</td>
</tr>
))}
</tbody>
</table>
)
) : typeof value === 'string' ? (
value
) : (
// Last resort
JSON.stringify(value, null, 2)
)}
</dd>
</>
))}
</dl>
)}
</div>
<hr />
<p style={{ textAlign: 'center' }}>
<Link to="/">
<Trans>Go home</Trans>
</Link>
</p>
</div>
);
}

View file

@ -39,6 +39,7 @@ import { getRegistration } from '../utils/push-notifications';
import shortenNumber from '../utils/shorten-number';
import showToast from '../utils/show-toast';
import states, { saveStatus } from '../utils/states';
import store from '../utils/store';
import { getCurrentInstance } from '../utils/store-utils';
import supports from '../utils/supports';
import usePageVisibility from '../utils/usePageVisibility';
@ -409,6 +410,45 @@ function Notifications({ columnMode }) {
// }
// }, [uiState]);
const [annualReportNotification, setAnnualReportNotification] =
useState(null);
useEffect(async () => {
// Skip this if not in December
const date = new Date();
if (date.getMonth() !== 11) return;
// Skip if doesn't support annual report
if (!supports('@mastodon/annual-report')) return;
let annualReportNotification = store.account.get(
'annualReportNotification',
);
if (annualReportNotification) {
setAnnualReportNotification(annualReportNotification);
return;
}
const notificationIterator = mastoFetchNotifications({
types: ['annual_report'],
});
try {
const notification = await notificationIterator.next();
annualReportNotification = notification?.value?.notificationGroups?.[0];
const annualReportYear = annualReportNotification?.annualReport?.year;
// If same year, show the annual report
if (annualReportYear == date.getFullYear()) {
console.log(
'ANNUAL REPORT',
annualReportYear,
annualReportNotification,
);
setAnnualReportNotification(annualReportNotification);
store.account.set('annualReportNotification', annualReportNotification);
}
} catch (e) {
console.warn(e);
}
}, []);
const itemsSelector = '.notification';
const jRef = useHotkeys('j', () => {
const activeItem = document.activeElement.closest(itemsSelector);
@ -728,6 +768,13 @@ function Notifications({ columnMode }) {
</div>
</div>
)}
{annualReportNotification && (
<div class="shazam-container">
<div class="shazam-container-inner">
<Notification notification={annualReportNotification} />
</div>
</div>
)}
<div id="mentions-option">
<label>
<input

View file

@ -1309,7 +1309,7 @@ function StatusThread({ id, closeLink = '/', instance: propInstance }) {
>
{statusesList}
{showMore > 0 && (
<li>
<li class="descendant descendant-more">
<button
type="button"
class="plain block show-more"

View file

@ -13,7 +13,7 @@ function escapeHTML(html) {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
}[c]),
})[c],
);
}

View file

@ -26,7 +26,7 @@ function statusPeek(status) {
video: '📹',
audio: '🎵',
unknown: '',
}[m.type] || ''),
})[m.type] || '',
)
.join('');
}