feat(notices): bring the release notes back on every update

The release modal takes the 4.3.0 design: the release and its headline cards
on the left, the note and the support links on the right, at the design's own
size. The cards carry small drawings of the features instead of an icon.

The 4.0.0 entry is retired. In its place sits one entry, release-notes, that
every big release rewrites and keeps. It recurs per version with no upper
bound, so every user sees it once on each update, whatever they did with it
before, and a reload of the same version keeps it closed. An integration test
holds that promise through the real entry and the real dismiss route.

All 23 locales carry the new copy and drop the 4.0.0 strings.
This commit is contained in:
Maurice
2026-09-15 23:50:15 +02:00
parent 99783cc8da
commit 05ee3d50e4
34 changed files with 1562 additions and 1206 deletions
@@ -1,14 +1,14 @@
// FE-RN-001 to FE-RN-011 // FE-RN-001 to FE-RN-014
import { describe, it, expect, vi } from 'vitest' import { describe, it, expect, vi } from 'vitest'
import { render, screen } from '../../../tests/helpers/render' import { render, screen } from '../../../tests/helpers/render'
import userEvent from '@testing-library/user-event' import userEvent from '@testing-library/user-event'
import { ReleaseNoticeModal } from './ReleaseNoticeModal' import { ReleaseNoticeModal } from './ReleaseNoticeModal'
import type { SystemNoticeDTO } from '../../store/systemNoticeStore' import type { SystemNoticeDTO } from '../../store/systemNoticeStore'
/** A notice shaped like the 4.0.0 registry entry, with the pieces a test needs to vary. */ /** A notice shaped like the release-notes registry entry, with the pieces a test needs to vary. */
function releaseNotice(overrides: Partial<SystemNoticeDTO> = {}): SystemNoticeDTO { function releaseNotice(overrides: Partial<SystemNoticeDTO> = {}): SystemNoticeDTO {
return { return {
id: 'release-4-0-0', id: 'release-notes',
display: 'modal', display: 'modal',
severity: 'info', severity: 'info',
titleKey: 'rel.headline', titleKey: 'rel.headline',
@@ -18,25 +18,27 @@ function releaseNotice(overrides: Partial<SystemNoticeDTO> = {}): SystemNoticeDT
cta: { kind: 'link', labelKey: 'rel.bmc', href: 'https://buymeacoffee.com/mauriceboe' }, cta: { kind: 'link', labelKey: 'rel.bmc', href: 'https://buymeacoffee.com/mauriceboe' },
secondaryCta: { kind: 'link', labelKey: 'rel.kofi', href: 'https://ko-fi.com/mauriceboe' }, secondaryCta: { kind: 'link', labelKey: 'rel.kofi', href: 'https://ko-fi.com/mauriceboe' },
release: { release: {
version: '4.0.0', version: '4.3.0',
eyebrowKey: 'rel.eyebrow', eyebrowKey: 'rel.eyebrow',
tagKey: 'rel.tag',
headlineKey: 'rel.headline', headlineKey: 'rel.headline',
introKey: 'rel.intro', introKey: 'rel.intro',
featuresLabelKey: 'rel.features.label',
features: [ features: [
{ iconName: 'Smartphone', titleKey: 'rel.f1.title', bodyKey: 'rel.f1.body' }, { iconName: 'Database', visual: 'places-api', titleKey: 'rel.f1.title', bodyKey: 'rel.f1.body' },
{ iconName: 'BookOpen', titleKey: 'rel.f2.title', bodyKey: 'rel.f2.body', badgeKey: 'rel.f2.badge' }, { iconName: 'Route', visual: 'roadtrip', titleKey: 'rel.f2.title', bodyKey: 'rel.f2.body' },
{ iconName: 'MapPin', visual: 'dawarich', titleKey: 'rel.f3.title', bodyKey: 'rel.f3.body' },
], ],
note: { note: {
eyebrowKey: 'rel.note.eyebrow', eyebrowKey: 'rel.note.eyebrow',
titleKey: 'rel.note.title', titleKey: 'rel.note.title',
bodyKey: 'rel.note.body', bodyKey: 'rel.note.body',
promiseLabelKey: 'rel.promise.label', promiseLabelKey: 'rel.promise.label',
promiseLeadKey: 'rel.promise.lead',
promiseTextKey: 'rel.promise.text', promiseTextKey: 'rel.promise.text',
bodyAfterKey: 'rel.note.after', bodyAfterKey: 'rel.note.after',
closingKey: 'rel.note.closing', closingKey: 'rel.note.closing',
signatureKey: 'rel.note.signature',
}, },
supportLeadKey: 'rel.support.lead',
supportTextKey: 'rel.support', supportTextKey: 'rel.support',
}, },
...overrides, ...overrides,
@@ -69,14 +71,16 @@ describe('ReleaseNoticeModal', () => {
it('FE-RN-002: shows the version as a plain figure, not a translation key', () => { it('FE-RN-002: shows the version as a plain figure, not a translation key', () => {
renderModal() renderModal()
expect(screen.getByText('4.0.0')).toBeInTheDocument() expect(screen.getByText('4.3.0')).toBeInTheDocument()
}) })
it('FE-RN-003: renders one row per feature, with the badge only where declared', () => { it('FE-RN-003: renders one card per feature, each with its drawing', () => {
renderModal() renderModal()
expect(screen.getByText('rel.f1.title')).toBeInTheDocument() expect(screen.getByText('rel.f1.title')).toBeInTheDocument()
expect(screen.getByText('rel.f2.badge')).toBeInTheDocument() expect(document.querySelectorAll('.rn-feature')).toHaveLength(3)
expect(document.querySelectorAll('.rn-feature')).toHaveLength(2) expect(document.querySelector('.rn-vis-places')).not.toBeNull()
expect(document.querySelector('.rn-vis-road')).not.toBeNull()
expect(document.querySelector('.rn-vis-trail')).not.toBeNull()
}) })
it('FE-RN-004: splits the note body on the blank line into separate paragraphs', () => { it('FE-RN-004: splits the note body on the blank line into separate paragraphs', () => {
@@ -88,17 +92,17 @@ describe('ReleaseNoticeModal', () => {
expect(screen.getByText('second paragraph')).toBeInTheDocument() expect(screen.getByText('second paragraph')).toBeInTheDocument()
}) })
it('FE-RN-005: omits the stats row when the release carries no stats', () => { it('FE-RN-005: omits the foot when the release has neither a footnote nor notes', () => {
renderModal() renderModal()
expect(document.querySelector('.rn-release-foot')).toBeNull() expect(document.querySelector('.rn-release-foot')).toBeNull()
}) })
it('FE-RN-006: shows the stats row and the notes link when both are present', () => { it('FE-RN-006: shows the footnote and the notes link when both are present', () => {
const n = releaseNotice() const n = releaseNotice()
n.release!.stats = [{ value: '~150', labelKey: 'rel.stat.bugs' }] n.release!.footnoteKey = 'rel.footnote'
n.release!.notes = { labelKey: 'rel.notes', href: 'https://example.test/notes' } n.release!.notes = { labelKey: 'rel.notes', href: 'https://example.test/notes' }
renderModal(n) renderModal(n)
expect(screen.getByText('~150')).toBeInTheDocument() expect(screen.getByText('rel.footnote')).toBeInTheDocument()
const link = screen.getByRole('link', { name: /rel\.notes/ }) const link = screen.getByRole('link', { name: /rel\.notes/ })
expect(link).toHaveAttribute('href', 'https://example.test/notes') expect(link).toHaveAttribute('href', 'https://example.test/notes')
expect(link).toHaveAttribute('target', '_blank') expect(link).toHaveAttribute('target', '_blank')
@@ -152,9 +156,37 @@ describe('ReleaseNoticeModal', () => {
renderModal() renderModal()
const dialog = screen.getByRole('dialog') const dialog = screen.getByRole('dialog')
expect(dialog).toHaveAttribute('aria-modal', 'true') expect(dialog).toHaveAttribute('aria-modal', 'true')
expect(dialog).toHaveAttribute('aria-labelledby', 'notice-title-release-4-0-0') expect(dialog).toHaveAttribute('aria-labelledby', 'notice-title-release-notes')
expect(dialog).toHaveAttribute('aria-describedby', 'notice-body-release-4-0-0') expect(dialog).toHaveAttribute('aria-describedby', 'notice-body-release-notes')
expect(document.getElementById('notice-title-release-4-0-0')).toHaveTextContent('rel.headline') expect(document.getElementById('notice-title-release-notes')).toHaveTextContent('rel.headline')
expect(document.getElementById('notice-body-release-4-0-0')).toHaveTextContent('rel.intro') expect(document.getElementById('notice-body-release-notes')).toHaveTextContent('rel.intro')
})
it('FE-RN-012: sets the promise and the support text with a bold lead', () => {
renderModal()
expect(screen.getByText('rel.promise.lead').tagName).toBe('B')
expect(screen.getByText('rel.support.lead').tagName).toBe('B')
expect(screen.getByText('rel.promise.text')).toBeInTheDocument()
})
it('FE-RN-013: the features aside is optional', () => {
renderModal()
expect(document.querySelector('.rn-features-aside')).toBeNull()
const n = releaseNotice()
n.release!.featuresAsideKey = 'rel.features.aside'
renderModal(n)
expect(screen.getByText('rel.features.aside')).toBeInTheDocument()
})
it('FE-RN-014: a card whose drawing this client does not know falls back to its icon', () => {
const n = releaseNotice()
n.release!.features = [
{ iconName: 'Route', visual: 'from-a-newer-server', titleKey: 'rel.x.title', bodyKey: 'rel.x.body' },
{ iconName: 'NoSuchIcon', titleKey: 'rel.y.title', bodyKey: 'rel.y.body' },
]
renderModal(n)
expect(document.querySelectorAll('.rn-vis-icon')).toHaveLength(2)
expect(document.querySelectorAll('.rn-vis-icon svg')).toHaveLength(2)
}) })
}) })
@@ -1,8 +1,8 @@
import React from 'react'; import React from 'react';
import * as LucideIcons from 'lucide-react'; import { ArrowRight, Heart, Infinity as InfinityIcon, X } from 'lucide-react';
import { ArrowRight, Coffee, Heart, Infinity as InfinityIcon, Sparkles, X } from 'lucide-react';
import { useTranslation } from '../../i18n/TranslationContext.js'; import { useTranslation } from '../../i18n/TranslationContext.js';
import type { SystemNoticeDTO } from '../../store/systemNoticeStore.js'; import type { SystemNoticeDTO } from '../../store/systemNoticeStore.js';
import { ReleaseFeatureVisual } from './ReleaseNoticeVisuals.js';
import './releaseNotice.css'; import './releaseNotice.css';
interface Props { interface Props {
@@ -13,6 +13,20 @@ interface Props {
onSecondaryCTA: () => void; onSecondaryCTA: () => void;
} }
/** Lucide's coffee cup, drawn here so its three steam strokes can drift up in waves. */
function SteamingCoffee() {
return (
<svg className="rn-coffee" width={18} height={18} viewBox="0 0 24 24" fill="none" stroke="currentColor"
strokeWidth={2.1} strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
<path d="M17 8h1a4 4 0 1 1 0 8h-1" />
<path d="M3 8h14v9a4 4 0 0 1-4 4H7a4 4 0 0 1-4-4Z" />
<path className="rn-steam" d="M6 5.5c-1.2-.9 1.2-1.7 0-2.6s1.2-1.7 0-2.6 1.2-1.7 0-2.6" />
<path className="rn-steam" d="M10 5.5c-1.2-.9 1.2-1.7 0-2.6s1.2-1.7 0-2.6 1.2-1.7 0-2.6" />
<path className="rn-steam" d="M14 5.5c-1.2-.9 1.2-1.7 0-2.6s1.2-1.7 0-2.6 1.2-1.7 0-2.6" />
</svg>
);
}
/** Splits a translated block into paragraphs the way the notice bodies are written. */ /** Splits a translated block into paragraphs the way the notice bodies are written. */
function paragraphs(text: string): string[] { function paragraphs(text: string): string[] {
return text.split('\n\n').map(p => p.trim()).filter(Boolean); return text.split('\n\n').map(p => p.trim()).filter(Boolean);
@@ -21,10 +35,10 @@ function paragraphs(text: string): string[] {
/** /**
* The release modal: what shipped on the left, a note from the maintainer on * The release modal: what shipped on the left, a note from the maintainer on
* the right. Rendered instead of the generic notice body whenever a notice * the right. Rendered instead of the generic notice body whenever a notice
* carries `release` — every string comes from that block, so a later release * carries `release`. Every string comes from that block, so a later release
* only edits the registry entry. * only edits the registry entry and its keys.
* *
* Desktop only (the notices carrying it set `desktopOnly`), and it keeps the * Desktop only (the notice carrying it sets `desktopOnly`), and it keeps the
* generic modal's behaviour: the host hook still owns ESC, the scroll lock and * generic modal's behaviour: the host hook still owns ESC, the scroll lock and
* the dismissal, this component only draws. * the dismissal, this component only draws.
*/ */
@@ -62,48 +76,37 @@ export function ReleaseNoticeModal({ notice, visible, onDismiss, onCTA, onSecond
<span className="rn-eyebrow">{t(release.eyebrowKey)}</span> <span className="rn-eyebrow">{t(release.eyebrowKey)}</span>
</div> </div>
<div className="rn-version-row"> <div className="rn-version">{release.version}</div>
<div className="rn-version">{release.version}</div>
<div className="rn-tag">{t(release.tagKey)}</div>
</div>
<h2 id={titleId} className="rn-headline">{t(release.headlineKey)}</h2> <h2 id={titleId} className="rn-headline">{t(release.headlineKey)}</h2>
<p id={bodyId} className="rn-intro">{t(release.introKey)}</p> <p id={bodyId} className="rn-intro">{t(release.introKey)}</p>
<div className="rn-features"> <div className="rn-features-head">
{release.features.map(f => { <span className="rn-features-label">{t(release.featuresLabelKey)}</span>
const Icon: React.ElementType = <span className="rn-features-rule" aria-hidden="true" />
((LucideIcons as Record<string, unknown>)[f.iconName] as React.ElementType) ?? Sparkles; {release.featuresAsideKey && (
return ( <span className="rn-features-aside">{t(release.featuresAsideKey)}</span>
<div key={f.titleKey} className="rn-feature"> )}
<span className="rn-feature-icon">
<Icon size={18} strokeWidth={1.9} aria-hidden="true" />
</span>
<div className="rn-feature-text">
<div className="rn-feature-title">
{t(f.titleKey)}
{f.badgeKey && <span className="rn-badge">{t(f.badgeKey)}</span>}
</div>
<div className="rn-feature-body">{t(f.bodyKey)}</div>
</div>
</div>
);
})}
</div> </div>
{((release.stats?.length ?? 0) > 0 || release.notes) && ( <div className="rn-features">
<div className="rn-release-foot"> {release.features.map(f => (
{release.stats && release.stats.length > 0 && ( <div key={f.titleKey} className="rn-feature">
<div className="rn-stats"> <div className="rn-feature-shine" aria-hidden="true" />
{release.stats.map(s => ( <div className="rn-feature-visual" aria-hidden="true">
<div key={s.labelKey}> <ReleaseFeatureVisual visual={f.visual} iconName={f.iconName} />
<div className="rn-stat-value">{s.value}</div>
<div className="rn-stat-label">{t(s.labelKey)}</div>
</div>
))}
</div> </div>
)} <div>
<div className="rn-feature-title">{t(f.titleKey)}</div>
<div className="rn-feature-body">{t(f.bodyKey)}</div>
</div>
</div>
))}
</div>
{(release.footnoteKey || release.notes) && (
<div className="rn-release-foot">
<div className="rn-footnote">{release.footnoteKey ? t(release.footnoteKey) : null}</div>
{release.notes && ( {release.notes && (
<a <a
className="rn-notes" className="rn-notes"
@@ -119,10 +122,6 @@ export function ReleaseNoticeModal({ notice, visible, onDismiss, onCTA, onSecond
)} )}
</div> </div>
)} )}
{release.footnoteKey && (
<div className="rn-footnote">{t(release.footnoteKey)}</div>
)}
</div> </div>
</div> </div>
@@ -130,7 +129,7 @@ export function ReleaseNoticeModal({ notice, visible, onDismiss, onCTA, onSecond
<div className="rn-note"> <div className="rn-note">
{notice.dismissible && ( {notice.dismissible && (
<button type="button" className="rn-close" onClick={onDismiss} aria-label={t('common.close')}> <button type="button" className="rn-close" onClick={onDismiss} aria-label={t('common.close')}>
<X size={18} strokeWidth={2} /> <X size={17} strokeWidth={2} />
</button> </button>
)} )}
@@ -145,19 +144,21 @@ export function ReleaseNoticeModal({ notice, visible, onDismiss, onCTA, onSecond
<InfinityIcon size={14} strokeWidth={2.1} aria-hidden="true" /> <InfinityIcon size={14} strokeWidth={2.1} aria-hidden="true" />
{t(release.note.promiseLabelKey)} {t(release.note.promiseLabelKey)}
</div> </div>
<div className="rn-promise-text">{t(release.note.promiseTextKey)}</div> <div className="rn-promise-text">
<b>{t(release.note.promiseLeadKey)}</b>{' '}
<span>{t(release.note.promiseTextKey)}</span>
</div>
</div> </div>
{paragraphs(t(release.note.bodyAfterKey)).map((p, i) => <p key={i}>{p}</p>)} {paragraphs(t(release.note.bodyAfterKey)).map((p, i) => <p key={i}>{p}</p>)}
<div className="rn-signoff"> <div className="rn-closing">{t(release.note.closingKey)}</div>
<div className="rn-closing">{t(release.note.closingKey)}</div>
<div className="rn-signature">{t(release.note.signatureKey)}</div>
</div>
</div> </div>
<div className="rn-support"> <div className="rn-support">
<div className="rn-support-text">{t(release.supportTextKey)}</div> <div className="rn-support-text">
<b>{t(release.supportLeadKey)}</b> {t(release.supportTextKey)}
</div>
<div className="rn-support-buttons"> <div className="rn-support-buttons">
{notice.cta && ( {notice.cta && (
<button type="button" <button type="button"
@@ -165,7 +166,7 @@ export function ReleaseNoticeModal({ notice, visible, onDismiss, onCTA, onSecond
className="rn-support-btn rn-support-bmc" className="rn-support-btn rn-support-bmc"
onClick={onCTA} onClick={onCTA}
> >
<Coffee size={18} strokeWidth={2.1} aria-hidden="true" /> <SteamingCoffee />
{t(notice.cta.labelKey)} {t(notice.cta.labelKey)}
</button> </button>
)} )}
@@ -175,7 +176,7 @@ export function ReleaseNoticeModal({ notice, visible, onDismiss, onCTA, onSecond
className="rn-support-btn rn-support-kofi" className="rn-support-btn rn-support-kofi"
onClick={onSecondaryCTA} onClick={onSecondaryCTA}
> >
<Heart size={18} strokeWidth={2.1} aria-hidden="true" /> <Heart className="rn-heart" size={18} strokeWidth={2.1} aria-hidden="true" />
{t(notice.secondaryCta.labelKey)} {t(notice.secondaryCta.labelKey)}
</button> </button>
)} )}
@@ -0,0 +1,85 @@
import React from 'react';
import * as LucideIcons from 'lucide-react';
import { Car, Landmark, Search, Sparkles } from 'lucide-react';
import DawarichIcon from '../shared/DawarichIcon';
import TrekMark from '../shared/TrekMark';
/*
* The small pictures on the release cards: pieces of TREK itself, drawn at card
* size rather than screenshotted, because a screenshot this small is a blur. They
* carry no words, only place names and figures that read the same in every
* language, so nothing here needs translating.
*/
function PlacesApiVisual() {
return (
<div className="rn-vis rn-vis-places">
<span className="rn-vis-trekbadge"><TrekMark className="rn-vis-trekmark" /></span>
<div className="rn-vis-search">
<Search size={11} strokeWidth={2.4} />
<span className="rn-vis-typed">Fushimi Inari</span>
<span className="rn-vis-caret" />
</div>
<div className="rn-vis-result">
<span className="rn-vis-cat" style={{ background: '#ef4444' }}><Landmark size={10} strokeWidth={2.2} /></span>
<span className="rn-vis-place">
<span>Fushimi Inari Taisha</span>
<small>Kyoto</small>
</span>
</div>
</div>
);
}
// The route and its stops, in the planner's own route blue and marker style.
const ROUTE = 'M26 84 C 58 82, 60 44, 96 46 S 136 74, 160 52 S 176 30, 182 28';
function RoadtripVisual() {
return (
<div className="rn-vis rn-vis-road">
<svg viewBox="0 0 200 112" preserveAspectRatio="xMidYMid slice" aria-hidden="true">
<path className="rn-vis-road-casing" d={ROUTE} />
<path className="rn-vis-road-line" d={ROUTE} />
</svg>
<span className="rn-vis-marker" style={{ left: '13%', top: '75%', background: '#6366f1' }}>1</span>
<span className="rn-vis-marker" style={{ left: '48%', top: '41%', background: '#f59e0b' }}>2</span>
<span className="rn-vis-marker" style={{ left: '91%', top: '25%', background: '#ec4899' }}>3</span>
<span className="rn-vis-distance"><Car size={10} strokeWidth={2.2} />386 km</span>
</div>
);
}
// A recorded day, with the two places the traveller stayed.
const TRAIL = '84,94 96,88 106,80 118,76 130,74 142,66 152,58 162,62 172,66 180,56 186,46';
const STAYS: Array<[number, number]> = [[130, 74], [186, 46]];
function DawarichVisual() {
return (
<div className="rn-vis rn-vis-trail">
<svg viewBox="0 0 200 112" preserveAspectRatio="xMidYMid slice" aria-hidden="true">
<polyline className="rn-vis-trail-line" points={TRAIL} />
{STAYS.map(([x, y]) => <circle key={x} className="rn-vis-trail-stay" cx={x} cy={y} r="3.4" />)}
</svg>
<span className="rn-vis-brand"><DawarichIcon size={58} /></span>
</div>
);
}
const VISUALS: Record<string, () => React.ReactElement> = {
'places-api': PlacesApiVisual,
roadtrip: RoadtripVisual,
dawarich: DawarichVisual,
};
/** The card's picture, or its icon when the release names no drawing this client knows. */
export function ReleaseFeatureVisual({ visual, iconName }: { visual?: string; iconName: string }) {
const Drawing = visual ? VISUALS[visual] : undefined;
if (Drawing) return <Drawing />;
const Icon: React.ElementType =
((LucideIcons as Record<string, unknown>)[iconName] as React.ElementType) ?? Sparkles;
return (
<div className="rn-vis rn-vis-icon">
<Icon size={30} strokeWidth={1.6} aria-hidden="true" />
</div>
);
}
@@ -1,22 +1,18 @@
/* /*
* The release notice modal — a two-column panel: the release on the left, * The release notice modal: a two-column panel, the release on the left and a
* a note from the maintainer on the right. * note from the maintainer on the right.
* *
* The measurements here are the design's own, kept in one stylesheet rather * The measurements are the design's own, at full size, kept in one stylesheet
* than spread across inline styles (the same arrangement mobile.css uses for * rather than spread across inline styles (the same arrangement mobile.css uses
* the mobile shell). Every one of them is multiplied by --rn-s, so the whole * for the mobile shell). The panel is 1420px wide wherever the screen has room
* panel scales as one piece and the proportions never drift: change that one * and gives up width, never size, where it has not.
* number to resize the modal.
* *
* The left column is deliberately dark in both themes: it is a brand panel, * The left column is deliberately dark in both themes: it is a brand panel, not
* not a surface, so it does not read the surface tokens. Everything on the * a surface, so it does not read the surface tokens. Everything on the right
* right does. * does. theme-lint-disable: the brand panel's colours are fixed by design.
*/ */
.rn-overlay { .rn-overlay {
/* Design is drawn at 1420px wide; anything below full size is this factor. */
--rn-s: 0.72;
position: fixed; position: fixed;
inset: 0; inset: 0;
/* Above the navbar, the page-bound sticky bars and the page-owned /* Above the navbar, the page-bound sticky bars and the page-owned
@@ -25,22 +21,13 @@
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
padding: 28px; padding: 34px;
background: oklch(0.12 0.01 60 / 0.52); background: oklch(0.12 0.01 60 / 0.52);
backdrop-filter: blur(14px) saturate(1.1); backdrop-filter: blur(14px) saturate(1.1);
-webkit-backdrop-filter: blur(14px) saturate(1.1); -webkit-backdrop-filter: blur(14px) saturate(1.1);
animation: rn-fade 0.35s ease both; animation: rn-fade 0.35s ease both;
} }
/* Roomy screens can carry a little more of the design's own scale. */
@media (min-width: 1900px) and (min-height: 1150px) {
.rn-overlay { --rn-s: 0.86; }
}
@media (max-width: 1280px), (max-height: 760px) {
.rn-overlay { --rn-s: 0.64; padding: 16px; }
}
@keyframes rn-fade { @keyframes rn-fade {
from { opacity: 0; } from { opacity: 0; }
to { opacity: 1; } to { opacity: 1; }
@@ -51,18 +38,30 @@
to { opacity: 1; transform: none; } to { opacity: 1; transform: none; }
} }
/*
* The design draws these boxes with their border outside the stated size, the
* browser default. TREK sets border-box globally, which would take 2px off each.
*/
.rn-panel,
.rn-mark,
.rn-feature,
.rn-feature-visual,
.rn-notes,
.rn-close { box-sizing: content-box; }
.rn-panel { .rn-panel {
width: calc(1420px * var(--rn-s)); width: min(1420px, calc(100% - 2px));
max-width: 100%;
max-height: 100%; max-height: 100%;
display: grid; display: grid;
grid-template-columns: 1.3fr 1fr; grid-template-columns: 1.2fr 1fr;
border-radius: calc(34px * var(--rn-s)); border-radius: 30px;
overflow: hidden; overflow: hidden;
box-shadow: 0 4px 12px oklch(0 0 0 / 0.2), 0 60px 130px -40px oklch(0 0 0 / 0.7); box-shadow: 0 4px 12px oklch(0 0 0 / 0.2), 0 60px 130px -40px oklch(0 0 0 / 0.7);
border: 1px solid oklch(1 0 0 / 0.1); border: 1px solid oklch(1 0 0 / 0.1);
animation: rn-rise 0.5s cubic-bezier(0.22, 1, 0.36, 1) both; animation: rn-rise 0.5s cubic-bezier(0.22, 1, 0.36, 1) both;
font-family: var(--font-system); font-family: var(--font-system);
/* The design sets no base line height; the app's 1.5 would add 3px to every label. */
line-height: normal;
} }
/* Below the two-column breakpoint the halves stack and the panel scrolls. */ /* Below the two-column breakpoint the halves stack and the panel scrolls. */
@@ -85,7 +84,7 @@
position: relative; position: relative;
background: radial-gradient(120% 95% at 18% 0%, #1b1b22 0%, #0e0e12 52%, #08080a 100%); background: radial-gradient(120% 95% at 18% 0%, #1b1b22 0%, #0e0e12 52%, #08080a 100%);
color: #f5f5f7; color: #f5f5f7;
padding: calc(50px * var(--rn-s)) calc(54px * var(--rn-s)) calc(38px * var(--rn-s)); padding: 44px 46px 34px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
overflow: hidden; overflow: hidden;
@@ -110,14 +109,17 @@
flex: 1; flex: 1;
min-height: 0; min-height: 0;
overflow-y: auto; overflow-y: auto;
scrollbar-width: none;
} }
.rn-eyebrow-row { display: flex; align-items: center; gap: calc(11px * var(--rn-s)); } .rn-release-inner::-webkit-scrollbar { display: none; }
.rn-eyebrow-row { display: flex; align-items: center; gap: 11px; }
.rn-mark { .rn-mark {
width: calc(32px * var(--rn-s)); width: 30px;
height: calc(32px * var(--rn-s)); height: 30px;
border-radius: calc(10px * var(--rn-s)); border-radius: 10px;
background: oklch(1 0 0 / 0.1); background: oklch(1 0 0 / 0.1);
border: 1px solid oklch(1 0 0 / 0.16); border: 1px solid oklch(1 0 0 / 0.16);
display: flex; display: flex;
@@ -126,167 +128,156 @@
flex: none; flex: none;
} }
.rn-mark img { .rn-mark img { width: 18px; height: 18px; display: block; }
width: calc(19px * var(--rn-s));
height: calc(19px * var(--rn-s));
display: block;
}
.rn-eyebrow { .rn-eyebrow,
.rn-features-label {
font-family: var(--font-subtext); font-family: var(--font-subtext);
font-size: calc(11.5px * var(--rn-s)); font-size: 11px;
line-height: 14px;
font-weight: 600; font-weight: 600;
letter-spacing: 0.2em; letter-spacing: 0.2em;
text-transform: uppercase; text-transform: uppercase;
color: oklch(1 0 0 / 0.5); color: oklch(1 0 0 / 0.5);
} }
.rn-version-row {
margin-top: calc(30px * var(--rn-s));
display: flex;
align-items: flex-end;
gap: calc(20px * var(--rn-s));
}
.rn-version { .rn-version {
margin-top: 22px;
font-family: var(--font-subtext); font-family: var(--font-subtext);
font-size: calc(112px * var(--rn-s)); font-size: 74px;
font-weight: 600; font-weight: 600;
line-height: 0.82; line-height: 0.84;
letter-spacing: -0.055em; letter-spacing: -0.055em;
color: #fbfbfd; color: #fbfbfd;
font-variant-numeric: tabular-nums;
}
.rn-tag {
padding-bottom: calc(11px * var(--rn-s));
font-size: calc(12.5px * var(--rn-s));
font-weight: 500;
letter-spacing: 0.14em;
text-transform: uppercase;
color: oklch(0.84 0.18 85);
} }
.rn-headline { .rn-headline {
/* CJK breaks anywhere by default; break at phrase boundaries where supported. */
word-break: auto-phrase; word-break: auto-phrase;
margin: calc(24px * var(--rn-s)) 0 0; margin: 20px 0 0;
font-size: calc(30px * var(--rn-s)); font-size: 26px;
font-weight: 600; font-weight: 600;
line-height: 1.22; line-height: 1.24;
letter-spacing: -0.03em; letter-spacing: -0.03em;
max-width: calc(600px * var(--rn-s)); max-width: 560px;
text-wrap: pretty; text-wrap: pretty;
} }
.rn-intro { .rn-intro {
margin: calc(13px * var(--rn-s)) 0 0; margin: 11px 0 0;
max-width: calc(620px * var(--rn-s)); max-width: 560px;
font-size: calc(15.5px * var(--rn-s)); font-size: 16.5px;
line-height: 1.62; line-height: 1.6;
color: oklch(1 0 0 / 0.62); color: oklch(1 0 0 / 0.62);
text-wrap: pretty; text-wrap: pretty;
} }
.rn-features { .rn-features-head {
margin-top: calc(30px * var(--rn-s)); margin-top: 28px;
display: flex; display: flex;
flex-direction: column; align-items: center;
gap: 14px;
}
.rn-features-label { white-space: nowrap; }
.rn-features-rule { flex: 1; height: 1px; background: oklch(1 0 0 / 0.12); }
.rn-features-aside {
font-size: 13px;
font-weight: 500;
color: oklch(1 0 0 / 0.4);
white-space: nowrap;
}
.rn-features {
margin-top: 14px;
/* Keeps the foot clear of the cards when the column has no height to spare. */
margin-bottom: 26px;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
gap: 14px;
} }
.rn-feature { .rn-feature {
position: relative;
display: flex; display: flex;
gap: calc(18px * var(--rn-s)); flex-direction: column;
padding: calc(16px * var(--rn-s)) 0; gap: 18px;
border-top: 1px solid oklch(1 0 0 / 0.09); min-height: 0;
padding: 14px 14px 18px;
border-radius: 20px;
background: linear-gradient(160deg, oklch(1 0 0 / 0.1) 0%, oklch(1 0 0 / 0.045) 62%);
border: 1px solid oklch(1 0 0 / 0.13);
backdrop-filter: blur(16px) saturate(1.2);
-webkit-backdrop-filter: blur(16px) saturate(1.2);
box-shadow: inset 0 1px 0 oklch(1 0 0 / 0.16), 0 12px 28px -16px oklch(0 0 0 / 0.7);
overflow: hidden;
} }
.rn-feature:last-child { border-bottom: 1px solid oklch(1 0 0 / 0.09); } .rn-feature-shine {
position: absolute;
.rn-feature-icon { top: 0;
width: calc(38px * var(--rn-s)); left: 0;
height: calc(38px * var(--rn-s)); right: 0;
flex: none; height: 1px;
border-radius: calc(12px * var(--rn-s)); background: linear-gradient(90deg, transparent, oklch(1 0 0 / 0.4), transparent);
background: oklch(1 0 0 / 0.07);
border: 1px solid oklch(1 0 0 / 0.1);
display: flex;
align-items: center;
justify-content: center;
color: oklch(0.9 0.16 88);
} }
.rn-feature-text { min-width: 0; } .rn-feature-visual {
position: relative;
height: 112px;
border-radius: 14px;
overflow: hidden;
background: oklch(1 0 0 / 0.06);
border: 1px solid oklch(1 0 0 / 0.12);
}
.rn-feature-title { .rn-feature-title {
font-size: calc(16.5px * var(--rn-s)); font-size: 17px;
font-weight: 600; font-weight: 600;
letter-spacing: -0.01em; line-height: 1.25;
} letter-spacing: -0.015em;
text-wrap: pretty;
.rn-badge {
display: inline-flex;
align-items: center;
margin-left: calc(4px * var(--rn-s));
padding: calc(3px * var(--rn-s)) calc(8px * var(--rn-s));
border-radius: calc(6px * var(--rn-s));
background: oklch(0.84 0.18 85 / 0.16);
border: 1px solid oklch(0.84 0.18 85 / 0.4);
font-family: var(--font-subtext);
font-size: calc(9.5px * var(--rn-s));
font-weight: 600;
letter-spacing: 0.14em;
text-transform: uppercase;
color: oklch(0.9 0.16 88);
vertical-align: 2px;
} }
.rn-feature-body { .rn-feature-body {
margin-top: calc(5px * var(--rn-s)); margin-top: 7px;
font-size: calc(14.5px * var(--rn-s)); font-size: 13.5px;
line-height: 1.55; line-height: 1.55;
color: oklch(1 0 0 / 0.58); color: oklch(1 0 0 / 0.6);
text-wrap: pretty; text-wrap: pretty;
} }
.rn-release-foot { .rn-release-foot {
margin-top: auto; margin-top: auto;
padding-top: calc(28px * var(--rn-s)); padding-top: 26px;
display: flex; display: flex;
align-items: flex-end; align-items: center;
justify-content: space-between; justify-content: space-between;
gap: calc(24px * var(--rn-s)); gap: 20px;
flex-wrap: wrap; border-top: 1px solid oklch(1 0 0 / 0.09);
} }
.rn-stats { display: flex; gap: calc(34px * var(--rn-s)); } .rn-footnote {
font-size: 14.5px;
.rn-stat-value { line-height: 1.55;
font-family: var(--font-subtext); color: oklch(1 0 0 / 0.46);
font-size: calc(20px * var(--rn-s)); max-width: 360px;
font-weight: 600; text-wrap: pretty;
letter-spacing: -0.02em;
font-variant-numeric: tabular-nums;
}
.rn-stat-label {
margin-top: calc(3px * var(--rn-s));
font-size: calc(11px * var(--rn-s));
letter-spacing: 0.1em;
text-transform: uppercase;
color: oklch(1 0 0 / 0.42);
} }
.rn-notes { .rn-notes {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
gap: calc(12px * var(--rn-s)); gap: 11px;
height: calc(46px * var(--rn-s)); height: 44px;
padding: 0 calc(8px * var(--rn-s)) 0 calc(20px * var(--rn-s)); padding: 0 7px 0 18px;
border-radius: 999px; border-radius: 999px;
background: oklch(1 0 0 / 0.07); background: oklch(1 0 0 / 0.07);
border: 1px solid oklch(1 0 0 / 0.14); border: 1px solid oklch(1 0 0 / 0.14);
color: #f5f5f7; color: #f5f5f7;
font-size: calc(14px * var(--rn-s)); font-size: 15px;
font-weight: 600; font-weight: 600;
white-space: nowrap; white-space: nowrap;
box-shadow: inset 0 1px 0 oklch(1 0 0 / 0.1); box-shadow: inset 0 1px 0 oklch(1 0 0 / 0.1);
@@ -298,10 +289,10 @@
.rn-notes:hover { background: oklch(1 0 0 / 0.12); color: #f5f5f7; } .rn-notes:hover { background: oklch(1 0 0 / 0.12); color: #f5f5f7; }
.rn-notes-arrow { .rn-notes-arrow {
width: calc(30px * var(--rn-s)); width: 30px;
height: calc(30px * var(--rn-s)); height: 30px;
border-radius: 50%; border-radius: 50%;
background: oklch(0.9 0.16 88); background: #f5f5f7;
color: #101013; color: #101013;
display: flex; display: flex;
align-items: center; align-items: center;
@@ -309,24 +300,192 @@
flex: none; flex: none;
} }
.rn-footnote { /* ── The card pictures ─────────────────────────────────────────────────── */
margin-top: calc(22px * var(--rn-s));
padding-top: calc(18px * var(--rn-s)); .rn-vis {
font-size: calc(14px * var(--rn-s)); position: absolute;
line-height: 1.6; inset: 0;
color: oklch(1 0 0 / 0.5); color: #f5f5f7;
text-wrap: pretty; font-family: var(--font-system);
} }
/* .rn-vis-road > svg,
* Its own rule so the footnote only draws a divider when something sits between .rn-vis-trail > svg { position: absolute; inset: 0; width: 100%; height: 100%; }
* it and the feature list. Without the stats row the list's closing border is
* already right above it, and two lines land on top of each other. .rn-vis-icon {
*/ display: flex;
.rn-release-foot + .rn-footnote { align-items: center;
border-top: 1px solid oklch(1 0 0 / 0.09); justify-content: center;
color: oklch(1 0 0 / 0.55);
} }
/* Places API: the index answering a search while it is typed. */
.rn-vis-places {
padding: 9px 12px;
display: flex;
flex-direction: column;
gap: 6px;
}
/* The same wordmark the API keys card leads with, centred; its pill text inverts against the tile. */
.rn-vis-trekbadge { align-self: center; display: flex; align-items: center; height: 24px; }
.rn-vis-trekmark { display: block; height: 20px; width: auto; color: #f5f5f7; }
.rn-vis-places .trek-mark .pill-fg { fill: #101013; }
.rn-vis-search {
display: flex;
align-items: center;
gap: 6px;
height: 22px;
padding: 0 9px;
border-radius: 8px;
background: oklch(1 0 0 / 0.08);
border: 1px solid oklch(1 0 0 / 0.16);
font-size: 10px;
font-weight: 500;
white-space: nowrap;
}
.rn-vis-search svg { width: 11px; height: 11px; flex: none; color: oklch(1 0 0 / 0.55); }
/* The query types itself out once, then the answer arrives under it. */
.rn-vis-typed {
display: inline-block;
max-width: 90px;
overflow: hidden;
white-space: nowrap;
animation: rn-type 1.3s steps(13, end) 0.7s both;
}
@keyframes rn-type { from { max-width: 0; } to { max-width: 90px; } }
.rn-vis-caret {
width: 1px;
height: 12px;
margin-left: -4px;
background: #f5f5f7;
animation: rn-caret 1s steps(1) infinite;
}
@keyframes rn-caret { 50% { opacity: 0; } }
.rn-vis-result {
display: flex;
align-items: center;
gap: 7px;
padding: 5px 8px;
border-radius: 8px;
background: oklch(1 0 0 / 0.07);
animation: rn-answer 0.3s ease 2.1s both;
}
@keyframes rn-answer { from { opacity: 0; transform: translateY(-3px); } to { opacity: 1; transform: none; } }
.rn-vis-cat {
width: 18px;
height: 18px;
border-radius: 50%;
border: 1.5px solid #ffffff;
color: #ffffff;
display: flex;
align-items: center;
justify-content: center;
flex: none;
box-sizing: border-box;
}
.rn-vis-place { display: flex; flex-direction: column; min-width: 0; line-height: 1.2; }
.rn-vis-place span {
font-size: 10px;
font-weight: 600;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.rn-vis-place small { font-size: 8.5px; color: oklch(1 0 0 / 0.5); }
@media (prefers-reduced-motion: reduce) {
.rn-vis-typed, .rn-vis-caret, .rn-vis-result { animation: none; }
}
[data-reduce-motion='true'] .rn-vis-typed,
[data-reduce-motion='true'] .rn-vis-caret,
[data-reduce-motion='true'] .rn-vis-result { animation: none; }
/* Road trip: the drive on the map, in the planner's route blue and marker style. */
.rn-vis-road-casing { fill: none; stroke: #0a5cc2; stroke-width: 5; stroke-linecap: round; stroke-linejoin: round; }
.rn-vis-road-line { fill: none; stroke: #0a84ff; stroke-width: 3; stroke-linecap: round; stroke-linejoin: round; }
.rn-vis-marker {
position: absolute;
width: 18px;
height: 18px;
margin: -9px 0 0 -9px;
border-radius: 50%;
border: 2px solid #ffffff;
box-sizing: border-box;
box-shadow: 0 1px 4px oklch(0 0 0 / 0.35);
color: #ffffff;
font-size: 8.5px;
font-weight: 700;
display: flex;
align-items: center;
justify-content: center;
font-variant-numeric: tabular-nums;
}
.rn-vis-distance {
position: absolute;
right: 9px;
bottom: 8px;
display: flex;
align-items: center;
gap: 4px;
padding: 2px 7px;
border-radius: 99px;
background: #f5f5f7;
color: #101013;
font-size: 9px;
font-weight: 600;
white-space: nowrap;
font-variant-numeric: tabular-nums;
}
/* Dawarich: a recorded day, in the trail colour the map draws it with. */
.rn-vis-trail-line { fill: none; stroke: #2563eb; stroke-width: 2.2; stroke-linecap: round; stroke-linejoin: round; }
.rn-vis-trail-stay { fill: #ffffff; stroke: #2563eb; stroke-width: 2; }
/* The mark itself, unframed, with its corners rounded like an app icon. */
.rn-vis-brand {
position: absolute;
top: 12px;
left: 12px;
width: 58px;
height: 58px;
border-radius: 15px;
overflow: hidden;
box-shadow: 0 4px 14px oklch(0 0 0 / 0.45), 0 0 0 1px oklch(1 0 0 / 0.14);
}
/* A glass sheen over the mark: a soft light from the top and a bright inner edge. */
.rn-vis-brand::after {
content: '';
position: absolute;
inset: 0;
border-radius: inherit;
background: linear-gradient(160deg, oklch(1 0 0 / 0.42) 0%, oklch(1 0 0 / 0.08) 38%, transparent 55%, oklch(0 0 0 / 0.12) 100%);
box-shadow: inset 0 1px 0 oklch(1 0 0 / 0.55), inset 0 0 0 1px oklch(1 0 0 / 0.22);
pointer-events: none;
}
.rn-vis-brand img { display: block; width: 100%; height: 100%; }
/* ── Right: the note ───────────────────────────────────────────────────── */ /* ── Right: the note ───────────────────────────────────────────────────── */
.rn-note { .rn-note {
@@ -340,10 +499,10 @@
.rn-close { .rn-close {
position: absolute; position: absolute;
top: calc(24px * var(--rn-s)); top: 22px;
right: calc(24px * var(--rn-s)); right: 22px;
width: calc(38px * var(--rn-s)); width: 36px;
height: calc(38px * var(--rn-s)); height: 36px;
border-radius: 50%; border-radius: 50%;
background: var(--bg-hover); background: var(--bg-hover);
border: 1px solid var(--border-faint); border: 1px solid var(--border-faint);
@@ -361,15 +520,19 @@
.rn-note-body { .rn-note-body {
flex: 1; flex: 1;
min-height: 0; min-height: 0;
padding: calc(50px * var(--rn-s)) calc(52px * var(--rn-s)) calc(30px * var(--rn-s)); padding: 44px 44px 26px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
overflow-y: auto; overflow-y: auto;
scrollbar-width: none;
} }
.rn-note-body::-webkit-scrollbar { display: none; }
.rn-note-eyebrow { .rn-note-eyebrow {
font-family: var(--font-subtext); font-family: var(--font-subtext);
font-size: calc(11.5px * var(--rn-s)); font-size: 11px;
line-height: 14px;
font-weight: 600; font-weight: 600;
letter-spacing: 0.2em; letter-spacing: 0.2em;
text-transform: uppercase; text-transform: uppercase;
@@ -377,103 +540,139 @@
} }
.rn-note-title { .rn-note-title {
/* CJK breaks anywhere by default; break at phrase boundaries where supported. */
word-break: auto-phrase; word-break: auto-phrase;
margin: calc(16px * var(--rn-s)) 0 0; margin: 14px 0 0;
font-size: calc(29px * var(--rn-s)); font-size: 29px;
font-weight: 600; font-weight: 600;
line-height: 1.2; line-height: 1.2;
letter-spacing: -0.03em; letter-spacing: -0.03em;
max-width: calc(420px * var(--rn-s)); max-width: 420px;
text-wrap: pretty; text-wrap: pretty;
} }
.rn-note p { .rn-note p {
margin: calc(20px * var(--rn-s)) 0 0; margin: 20px 0 0;
font-size: calc(15px * var(--rn-s)); font-size: 16px;
line-height: 1.68; line-height: 1.66;
color: var(--text-secondary); color: var(--text-secondary);
text-wrap: pretty; text-wrap: pretty;
} }
.rn-note p + p { margin-top: calc(15px * var(--rn-s)); } .rn-note p + p { margin-top: 14px; }
/*
* The promise is a pane of glass in the inverse of the note: dark on a light note,
* light on a dark one, with the same sheen and edge light as the release cards.
*/
.rn-promise { .rn-promise {
margin-top: calc(24px * var(--rn-s)); position: relative;
padding: calc(20px * var(--rn-s)) calc(22px * var(--rn-s)); isolation: isolate;
border-radius: calc(20px * var(--rn-s)); overflow: hidden;
background: oklch(0.72 0.11 190 / 0.1); margin-top: 24px;
border: 1px solid oklch(0.72 0.11 190 / 0.28); padding: 18px 20px;
border-radius: 18px;
background: linear-gradient(
160deg,
color-mix(in oklch, var(--text-primary) 94%, transparent) 0%,
color-mix(in oklch, var(--text-primary) 80%, transparent) 100%
);
border: 1px solid color-mix(in oklch, var(--text-primary) 55%, transparent);
backdrop-filter: blur(16px) saturate(1.3);
-webkit-backdrop-filter: blur(16px) saturate(1.3);
box-shadow: inset 0 1px 0 oklch(1 0 0 / 0.2), 0 16px 34px -20px oklch(0 0 0 / 0.6);
color: var(--bg-primary);
}
/* The edge light along the top, as on the cards. */
.rn-promise::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 1px;
background: linear-gradient(90deg, transparent, oklch(1 0 0 / 0.5), transparent);
z-index: 1;
}
/* A soft light falling in from the top left, and a faint glow where it leaves. */
.rn-promise::after {
content: '';
position: absolute;
inset: 0;
background:
radial-gradient(120% 110% at 0% 0%, oklch(1 0 0 / 0.16) 0%, transparent 55%),
radial-gradient(80% 90% at 100% 100%, oklch(0.84 0.18 85 / 0.12) 0%, transparent 60%);
pointer-events: none;
z-index: -1;
} }
.rn-promise-label { .rn-promise-label {
display: flex; display: flex;
align-items: center; align-items: center;
gap: calc(9px * var(--rn-s)); gap: 9px;
font-family: var(--font-subtext); font-family: var(--font-subtext);
font-size: calc(11px * var(--rn-s)); font-size: 10.5px;
font-weight: 600; font-weight: 600;
letter-spacing: 0.16em; letter-spacing: 0.16em;
text-transform: uppercase; text-transform: uppercase;
color: oklch(0.55 0.09 190); color: color-mix(in oklch, var(--bg-primary) 55%, transparent);
} }
.dark .rn-promise-label { color: oklch(0.78 0.1 190); }
.rn-promise-text { .rn-promise-text {
margin-top: calc(10px * var(--rn-s)); margin-top: 9px;
font-size: calc(15.5px * var(--rn-s)); font-size: 16.5px;
font-weight: 600; line-height: 1.5;
line-height: 1.55;
letter-spacing: -0.01em; letter-spacing: -0.01em;
text-wrap: pretty; text-wrap: pretty;
} }
.rn-signoff { margin-top: auto; padding-top: calc(26px * var(--rn-s)); } .rn-promise-text b { font-weight: 600; }
.rn-promise-text span { font-weight: 400; color: color-mix(in oklch, var(--bg-primary) 68%, transparent); }
.rn-closing { .rn-closing {
font-size: calc(18px * var(--rn-s)); margin-top: auto;
padding-top: 24px;
font-size: 16.5px;
font-weight: 600; font-weight: 600;
letter-spacing: -0.02em; letter-spacing: -0.02em;
color: var(--text-primary); color: var(--text-primary);
} }
.rn-signature {
margin-top: calc(8px * var(--rn-s));
font-size: calc(15px * var(--rn-s));
font-weight: 500;
color: var(--text-secondary);
}
.rn-support { .rn-support {
padding: calc(26px * var(--rn-s)) calc(52px * var(--rn-s)) calc(34px * var(--rn-s)); padding: 22px 44px 26px;
border-top: 1px solid var(--border-primary); border-top: 1px solid var(--border-primary);
background: var(--bg-secondary); background: var(--bg-hover);
} }
.rn-support-text { .rn-support-text {
font-size: calc(15px * var(--rn-s)); font-size: 15.5px;
line-height: 1.68; line-height: 1.62;
color: var(--text-secondary); color: var(--text-secondary);
text-wrap: pretty; text-wrap: pretty;
} }
.rn-support-text b { font-weight: 600; color: var(--text-primary); }
.rn-support-buttons { .rn-support-buttons {
margin-top: calc(16px * var(--rn-s)); margin-top: 14px;
display: grid; display: grid;
grid-template-columns: 1fr 1fr; grid-template-columns: 1fr 1fr;
gap: calc(10px * var(--rn-s)); gap: 10px;
} }
.rn-support-btn { .rn-support-btn {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
gap: calc(9px * var(--rn-s)); gap: 9px;
height: calc(50px * var(--rn-s)); height: 50px;
border-radius: calc(16px * var(--rn-s)); border-radius: 15px;
font-size: calc(14.5px * var(--rn-s)); font-size: 15.5px;
font-weight: 600; font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.04em;
box-shadow: 0 2px 6px oklch(0 0 0 / 0.1); box-shadow: 0 2px 6px oklch(0 0 0 / 0.1);
cursor: pointer; cursor: pointer;
border: 0; border: 0;
@@ -482,19 +681,41 @@
.rn-support-btn:hover { filter: brightness(0.96); } .rn-support-btn:hover { filter: brightness(0.96); }
/* Brand colours — theme-lint-disable: Buy Me a Coffee and Ko-fi own these. */ /* The steam lifts off the cup in turn, and the heart beats. */
.rn-support-bmc { background: #ffdd00; color: #101013; } .rn-coffee { overflow: visible; }
.rn-support-kofi { background: #ff5e5b; color: #ffffff; } .rn-steam { stroke-width: 1.8; animation: rn-steam 3s ease-in-out infinite; }
.rn-steam:nth-of-type(4) { animation-delay: 0.5s; }
.rn-steam:nth-of-type(5) { animation-delay: 1s; }
@keyframes rn-steam {
0% { opacity: 0; transform: translate(0, 3px); }
25% { opacity: 1; transform: translate(-0.7px, -1px); }
55% { opacity: 0.85; transform: translate(0.7px, -5px); }
100% { opacity: 0; transform: translate(-0.4px, -10px); }
}
.rn-heart { transform-origin: 50% 55%; animation: rn-beat 1.3s ease-in-out infinite; }
@keyframes rn-beat {
0%, 60%, 100% { transform: scale(1); }
15% { transform: scale(1.2); }
30% { transform: scale(1); }
45% { transform: scale(1.12); }
}
@media (prefers-reduced-motion: reduce) {
.rn-steam, .rn-heart { animation: none; }
}
[data-reduce-motion='true'] .rn-steam,
[data-reduce-motion='true'] .rn-heart { animation: none; }
/* Brand colours: Buy Me a Coffee and Ko-fi own these. */
.rn-support-bmc { background: #ffdd00; color: #101013; } /* theme-lint-disable */
.rn-support-kofi { background: #ff5e5b; color: #ffffff; } /* theme-lint-disable */
/* Narrow viewports: keep the proportions, drop the outer padding. */ /* Narrow viewports: keep the proportions, drop the outer padding. */
@media (max-width: 900px) { @media (max-width: 900px) {
.rn-overlay { padding: 0; } .rn-overlay { padding: 0; }
.rn-panel { border-radius: 0; border: 0; max-height: 100%; } .rn-panel { border-radius: 0; border: 0; max-height: 100%; }
} }
/* Icons carry fixed size attributes from lucide; scale them with the panel. */
.rn-feature-icon svg { width: calc(18px * var(--rn-s)); height: calc(18px * var(--rn-s)); }
.rn-notes-arrow svg { width: calc(16px * var(--rn-s)); height: calc(16px * var(--rn-s)); }
.rn-promise-label svg { width: calc(14px * var(--rn-s)); height: calc(14px * var(--rn-s)); flex: none; }
.rn-support-btn svg { width: calc(18px * var(--rn-s)); height: calc(18px * var(--rn-s)); flex: none; }
.rn-close svg { width: calc(18px * var(--rn-s)); height: calc(18px * var(--rn-s)); }
+51 -55
View File
@@ -31,92 +31,88 @@ export const RETIRED_NOTICE_IDS = [
'v3-mcp', 'v3-mcp',
'v3-features', 'v3-features',
'welcome-v1', 'welcome-v1',
'release-4-0-0',
] as const; ] as const;
export const SYSTEM_NOTICES: SystemNotice[] = [ export const SYSTEM_NOTICES: SystemNotice[] = [
// ── 4.0.0 release — what shipped, and a note from the maintainer ──────────── // ── Release notes: what the current release brought, and a note from the maintainer ──
// Carries `release`, so it renders as the two-column release modal rather than // One entry for every release. Each big release swaps the copy (the release_notes
// the generic notice body. 4.0.0 was big enough that the whole 4.x line should // keys) and the version below, and keeps this id. `recurring: 'per-version'` brings
// carry it, so `recurring: 'per-version'` brings it back on each upgrade inside // it back to every user on every upgrade, a patch release included, so nobody is
// the window rather than the default one-time dismissal, which retired it for // ever left on a version with nothing to show. No upper bound for the same reason.
// everyone who closed it once on 4.0.0. A 5.x release gets its own entry.
{ {
id: 'release-4-0-0', id: 'release-notes',
recurring: 'per-version', recurring: 'per-version',
display: 'modal', display: 'modal',
severity: 'info', severity: 'info',
titleKey: 'system_notice.release_400.headline', titleKey: 'system_notice.release_notes.headline',
bodyKey: 'system_notice.release_400.intro', bodyKey: 'system_notice.release_notes.intro',
release: { release: {
version: '4.0.0', version: '4.3.0',
eyebrowKey: 'system_notice.release_400.eyebrow', eyebrowKey: 'system_notice.release_notes.eyebrow',
tagKey: 'system_notice.release_400.tag', headlineKey: 'system_notice.release_notes.headline',
headlineKey: 'system_notice.release_400.headline', introKey: 'system_notice.release_notes.intro',
introKey: 'system_notice.release_400.intro', featuresLabelKey: 'system_notice.release_notes.features_label',
featuresAsideKey: 'system_notice.release_notes.features_aside',
features: [ features: [
{ {
iconName: 'Smartphone', iconName: 'Database',
titleKey: 'system_notice.release_400.feature_mobile_title', visual: 'places-api',
bodyKey: 'system_notice.release_400.feature_mobile_body', titleKey: 'system_notice.release_notes.feature_places_title',
bodyKey: 'system_notice.release_notes.feature_places_body',
}, },
{ {
iconName: 'BookOpen', iconName: 'Route',
titleKey: 'system_notice.release_400.feature_studio_title', visual: 'roadtrip',
bodyKey: 'system_notice.release_400.feature_studio_body', titleKey: 'system_notice.release_notes.feature_roadtrip_title',
badgeKey: 'system_notice.release_400.feature_studio_badge', bodyKey: 'system_notice.release_notes.feature_roadtrip_body',
}, },
{ {
iconName: 'CalendarDays', iconName: 'MapPin',
titleKey: 'system_notice.release_400.feature_vacay_title', visual: 'dawarich',
bodyKey: 'system_notice.release_400.feature_vacay_body', titleKey: 'system_notice.release_notes.feature_dawarich_title',
}, bodyKey: 'system_notice.release_notes.feature_dawarich_body',
{
iconName: 'Image',
titleKey: 'system_notice.release_400.feature_places_title',
bodyKey: 'system_notice.release_400.feature_places_body',
}, },
], ],
// No stat row and no notes button here: the left column reads better short. footnoteKey: 'system_notice.release_notes.footnote',
footnoteKey: 'system_notice.release_400.footnote', notes: {
note: { labelKey: 'system_notice.release_notes.notes_label',
eyebrowKey: 'system_notice.release_400.note_eyebrow', href: 'https://github.com/liketrek/TREK/releases/tag/v4.3.0',
titleKey: 'system_notice.release_400.note_title',
bodyKey: 'system_notice.release_400.note_body',
promiseLabelKey: 'system_notice.release_400.promise_label',
promiseTextKey: 'system_notice.release_400.promise_text',
bodyAfterKey: 'system_notice.release_400.note_body_after',
closingKey: 'system_notice.release_400.note_closing',
signatureKey: 'system_notice.release_400.note_signature',
}, },
supportTextKey: 'system_notice.release_400.support_text', note: {
eyebrowKey: 'system_notice.release_notes.note_eyebrow',
titleKey: 'system_notice.release_notes.note_title',
bodyKey: 'system_notice.release_notes.note_body',
promiseLabelKey: 'system_notice.release_notes.promise_label',
promiseLeadKey: 'system_notice.release_notes.promise_lead',
promiseTextKey: 'system_notice.release_notes.promise_text',
bodyAfterKey: 'system_notice.release_notes.note_body_after',
closingKey: 'system_notice.release_notes.note_closing',
},
supportLeadKey: 'system_notice.release_notes.support_lead',
supportTextKey: 'system_notice.release_notes.support_text',
}, },
cta: { cta: {
kind: 'link', kind: 'link',
labelKey: 'system_notice.release_400.cta_bmc', labelKey: 'system_notice.release_notes.cta_bmc',
href: 'https://buymeacoffee.com/mauriceboe', href: 'https://buymeacoffee.com/mauriceboe',
}, },
secondaryCta: { secondaryCta: {
kind: 'link', kind: 'link',
labelKey: 'system_notice.release_400.cta_kofi', labelKey: 'system_notice.release_notes.cta_kofi',
href: 'https://ko-fi.com/mauriceboe', href: 'https://ko-fi.com/mauriceboe',
}, },
dismissible: true, dismissible: true,
// Desktop-only, like the thank-you modal it replaces: the two-column layout // Desktop-only: the two-column layout has no phone form, and the phone has its
// has no phone form, and the mobile release lands with its own onboarding. // own onboarding.
desktopOnly: true, desktopOnly: true,
// Same reasoning as the thank-you notice below: it asks the reader to fund // It asks the reader to fund the project, and on a managed install they already
// the project, and on a managed install they already pay whoever runs it. // pay whoever runs it.
conditions: [{ kind: 'managed', is: false }], conditions: [{ kind: 'managed', is: false }],
publishedAt: '2026-08-22T00:00:00Z', publishedAt: '2026-09-15T00:00:00Z',
priority: 110, priority: 110,
// The whole 4.x line. The copy is about what 4.0.0 brought, and that is still // Where the thank-you notice below hands over; nothing on 3.x ships this copy.
// what somebody arriving anywhere on 4.x is being introduced to — the minor
// releases after it add to that picture rather than replace it. Held open to
// the 5.0.0 boundary (exclusive) so a 4.1/4.2 install is not left with no
// notice at all, which is what a per-release window did the moment 4.1.0
// shipped without an entry of its own.
minVersion: '4.0.0', minVersion: '4.0.0',
maxVersion: '5.0.0',
}, },
// ── Thank-you + support the project — shown once per install AND once per upgrade ── // ── Thank-you + support the project — shown once per install AND once per upgrade ──
+6 -10
View File
@@ -30,15 +30,10 @@ export type NoticeCta =
export interface NoticeReleaseFeature { export interface NoticeReleaseFeature {
iconName: string; iconName: string;
/** A small illustration the client draws on the card; unknown names fall back to the icon. */
visual?: string;
titleKey: string; titleKey: string;
bodyKey: string; bodyKey: string;
badgeKey?: string;
}
export interface NoticeReleaseStat {
/** The figure itself ("~150") — shown as-is, never translated. */
value: string;
labelKey: string;
} }
/** /**
@@ -49,11 +44,11 @@ export interface NoticeReleaseStat {
export interface NoticeRelease { export interface NoticeRelease {
version: string; version: string;
eyebrowKey: string; eyebrowKey: string;
tagKey: string;
headlineKey: string; headlineKey: string;
introKey: string; introKey: string;
featuresLabelKey: string;
featuresAsideKey?: string;
features: NoticeReleaseFeature[]; features: NoticeReleaseFeature[];
stats?: NoticeReleaseStat[];
notes?: { labelKey: string; href: string }; notes?: { labelKey: string; href: string };
footnoteKey?: string; footnoteKey?: string;
note: { note: {
@@ -61,11 +56,12 @@ export interface NoticeRelease {
titleKey: string; titleKey: string;
bodyKey: string; bodyKey: string;
promiseLabelKey: string; promiseLabelKey: string;
promiseLeadKey: string;
promiseTextKey: string; promiseTextKey: string;
bodyAfterKey: string; bodyAfterKey: string;
closingKey: string; closingKey: string;
signatureKey: string;
}; };
supportLeadKey: string;
supportTextKey: string; supportTextKey: string;
} }
+42 -1
View File
@@ -97,7 +97,7 @@ describe('GET /api/system-notices/active', () => {
// login_count > 1 means firstLogin does not match; first_seen_version >= 3.0.0 means // login_count > 1 means firstLogin does not match; first_seen_version >= 3.0.0 means
// existingUserBeforeVersion('3.0.0') does not match either. Notices that gate on // existingUserBeforeVersion('3.0.0') does not match either. Notices that gate on
// nothing but the install being self-hosted still apply, and which ones those are // nothing but the install being self-hosted still apply, and which ones those are
// changes every release — the thank-you modal handed over to release-4-0-0 at 4.0.0. // changes every release (the thank-you modal handed over to the release notes at 4.0.0).
// Read the set out of the registry rather than naming them, or this ages out again. // Read the set out of the registry rather than naming them, or this ages out again.
testDb.prepare('UPDATE users SET login_count = 5, first_seen_version = ? WHERE id = ?').run('3.0.0', user.id); testDb.prepare('UPDATE users SET login_count = 5, first_seen_version = ? WHERE id = ?').run('3.0.0', user.id);
const alwaysOn = new Set( const alwaysOn = new Set(
@@ -226,6 +226,47 @@ describe('GET /api/system-notices/active', () => {
if (idx !== -1) SYSTEM_NOTICES.splice(idx, 1); if (idx !== -1) SYSTEM_NOTICES.splice(idx, 1);
} }
}); });
// The release notes carry the support links, so the promise is exact: once per
// update for every user, whatever they did with it before, and never again on a
// reload of the same version. Driven through the real registry entry and the real
// dismiss route, so neither half can drift away from the other unnoticed.
it('shows the release notes once per update, however often they were closed before', async () => {
const { user } = createUser(testDb);
testDb.prepare('UPDATE users SET login_count = 5, first_seen_version = ? WHERE id = ?').run('3.0.0', user.id);
const shows = async () => {
const res = await request(app)
.get('/api/system-notices/active')
.set('Cookie', authCookie(user.id));
expect(res.status).toBe(200);
return res.body.some((n: { id: string }) => n.id === 'release-notes');
};
const dismiss = async () => {
const res = await request(app)
.post('/api/system-notices/release-notes/dismiss')
.set('Cookie', authCookie(user.id));
expect(res.status).toBe(204);
};
expect(await shows()).toBe(true);
// Closed on this version: gone for every reload after it.
await dismiss();
expect(await shows()).toBe(false);
expect(await shows()).toBe(false);
// The next update brings it back, although it was closed before...
testDb.prepare(
'UPDATE user_notice_dismissals SET dismissed_app_version = ? WHERE user_id = ? AND notice_id = ?'
).run('4.0.0', user.id, 'release-notes');
expect(await shows()).toBe(true);
expect(await shows()).toBe(true);
// ...and closing it again holds until the one after that.
await dismiss();
expect(await shows()).toBe(false);
});
}); });
// ───────────────────────────────────────────────────────────────────────────── // ─────────────────────────────────────────────────────────────────────────────
@@ -2,7 +2,7 @@ import { describe, it, expect } from 'vitest';
import fs from 'node:fs'; import fs from 'node:fs';
import path from 'node:path'; import path from 'node:path';
import semver from 'semver'; import semver from 'semver';
import { SYSTEM_NOTICES } from '../../../src/systemNotices/registry.js'; import { RETIRED_NOTICE_IDS, SYSTEM_NOTICES } from '../../../src/systemNotices/registry.js';
import { isNoticeVersionActive } from '../../../src/systemNotices/service.js'; import { isNoticeVersionActive } from '../../../src/systemNotices/service.js';
/** Collect all actionIds registered via registerNoticeAction() in client source files. */ /** Collect all actionIds registered via registerNoticeAction() in client source files. */
@@ -65,29 +65,28 @@ describe('registry integrity', () => {
} }
}); });
it('the 4.0.0 release notice covers the whole 4.x line', () => { it('the release notes come back on every upgrade, with no upper bound', () => {
const release = SYSTEM_NOTICES.find(n => n.id === 'release-4-0-0'); const release = SYSTEM_NOTICES.find(n => n.id === 'release-notes');
expect(release).toBeDefined(); expect(release).toBeDefined();
// It must not greet somebody still on 3.x... // Nothing on 3.x ships this copy, and the thank-you notice still covers it there.
expect(isNoticeVersionActive(release!, '3.4.1')).toBe(false); expect(isNoticeVersionActive(release!, '3.4.1')).toBe(false);
expect(isNoticeVersionActive(release!, '4.0.0')).toBe(true); // From there on every version carries it, a patch release included, so no
expect(isNoticeVersionActive(release!, '4.0.7')).toBe(true); // install is left with nothing to show because nobody wrote a new window.
expect(isNoticeVersionActive(release!, '4.0.12')).toBe(true); for (const version of ['4.0.0', '4.2.1', '4.3.0', '4.3.1', '4.9.9', '5.0.0', '12.4.0']) {
// ...and it stays up across the minors, so no 4.x install is left without a expect(isNoticeVersionActive(release!, version), version).toBe(true);
// notice the way 4.1.0 was under the old per-release window. }
expect(isNoticeVersionActive(release!, '4.1.0')).toBe(true); expect(release!.maxVersion).toBeUndefined();
expect(isNoticeVersionActive(release!, '4.2.0')).toBe(true); // The window alone is not enough: a one-time dismissal would retire it for good
expect(isNoticeVersionActive(release!, '4.9.9')).toBe(true); // the first time somebody closed it.
// The upper bound is exclusive: 5.0.0 gets its own notice. expect(release!.recurring).toBe('per-version');
expect(isNoticeVersionActive(release!, '5.0.0')).toBe(false);
}); });
it('the 4.0.0 release notice comes back on each upgrade inside that line', () => { it('the 4.0.0 release notice is retired and its id stays reserved', () => {
const release = SYSTEM_NOTICES.find(n => n.id === 'release-4-0-0')!; expect(SYSTEM_NOTICES.some(n => n.id === 'release-4-0-0')).toBe(false);
// The version window above is only half of "covers the whole 4.x line". Without expect(RETIRED_NOTICE_IDS).toContain('release-4-0-0');
// this, the default one-time dismissal retired the notice for everyone who for (const id of RETIRED_NOTICE_IDS) {
// closed it on 4.0.0, so none of them saw it again on 4.1, 4.2 or later. expect(SYSTEM_NOTICES.some(n => n.id === id), id).toBe(false);
expect(release.recurring).toBe('per-version'); }
}); });
it('the thank-you notice hands over to the release modal at 4.0.0', () => { it('the thank-you notice hands over to the release modal at 4.0.0', () => {
@@ -98,10 +97,10 @@ describe('registry integrity', () => {
expect(isNoticeVersionActive(thankYou!, '3.4.1')).toBe(true); expect(isNoticeVersionActive(thankYou!, '3.4.1')).toBe(true);
expect(isNoticeVersionActive(thankYou!, '4.0.0')).toBe(false); expect(isNoticeVersionActive(thankYou!, '4.0.0')).toBe(false);
const release = SYSTEM_NOTICES.find(n => n.id === 'release-4-0-0')!; const release = SYSTEM_NOTICES.find(n => n.id === 'release-notes')!;
for (const version of ['3.4.1', '4.0.0', '4.0.7', '4.1.0', '5.0.0']) { for (const version of ['3.4.1', '4.0.0', '4.0.7', '4.1.0', '4.3.0', '5.0.0']) {
const active = [thankYou!, release].filter(n => isNoticeVersionActive(n, version)); const active = [thankYou!, release].filter(n => isNoticeVersionActive(n, version));
expect(active.length, `both thank-you notices active at ${version}`).toBeLessThanOrEqual(1); expect(active.length, `thank-you and release notes at ${version}`).toBe(1);
} }
}); });
}); });
+6
View File
@@ -35,6 +35,12 @@ export const ALLOWED = [
'settings.about.descriptionManaged instead, so neither reader is told the ' + 'settings.about.descriptionManaged instead, so neither reader is told the ' +
'wrong thing and self-hosters lose nothing.', 'wrong thing and self-hosters lose nothing.',
}, },
{
key: 'system_notice.release_notes.feature_dawarich_body',
because:
'it calls Dawarich self-hosted, not TREK, which is what Dawarich is, and the ' +
'release notice carrying it is shown only where the managed condition is false',
},
{ {
key: 'system_notice.v3_thankyou.body', key: 'system_notice.v3_thankyou.body',
because: because:
+33 -35
View File
@@ -53,40 +53,38 @@ const system_notice: TranslationStrings = {
'system_notice.thank_you_support.cta_bmc': 'Buy Me a Coffee', 'system_notice.thank_you_support.cta_bmc': 'Buy Me a Coffee',
'system_notice.thank_you_support.cta_kofi': 'ادعمني على Ko-fi', 'system_notice.thank_you_support.cta_kofi': 'ادعمني على Ko-fi',
'system_notice.pager.counter': '{current} / {total}', // en-fallback 'system_notice.pager.counter': '{current} / {total}', // en-fallback
'system_notice.release_400.eyebrow': 'تم تثبيت التحديث', 'system_notice.release_notes.eyebrow': 'تم تثبيت التحديث',
'system_notice.release_400.tag': 'إصدار', 'system_notice.release_notes.headline': 'ثلاثة أشياء صار TREK يتولاها بنفسه.',
'system_notice.release_400.headline': 'أكبر إصدار حظي به TREK على الإطلاق.', 'system_notice.release_notes.intro':
'system_notice.release_400.intro': 'واجهة API خاصة به للأماكن، ورحلات برية مخطَّطة من أولها إلى آخرها، وسجل مواقعك يعود إلى يديك.',
'يحصل TREK على هاتف، وعلى كتاب. تسعة عشر شخصًا كتبوا هذا الإصدار — ومعه نحو مئة وخمسين بلاغ خطأ تم إصلاحها.', 'system_notice.release_notes.features_label': 'أبرز الجديد',
'system_notice.release_400.feature_mobile_title': 'TREK على الهاتف', 'system_notice.release_notes.features_aside': 'وهذا ليس كل شيء',
'system_notice.release_400.feature_mobile_body': 'system_notice.release_notes.feature_places_title': 'TREK Places API',
'كل ما دون 768px صار واجهة مستقلة — شريط زجاجي، ولوحات منزلقة خاصة به، ومخطط رحلة خاص به. افتح TREK على هاتفك.', 'system_notice.release_notes.feature_places_body':
'system_notice.release_400.feature_studio_title': 'TREK Studio', 'أول مخطط سفر مفتوح المصدر يستضيف واجهة API خاصة به للأماكن. 73.6 مليون مكان، يُعاد بناؤها كل شهر. بلا مفتاح ولا حصة.',
'system_notice.release_400.feature_studio_badge': 'Beta', 'system_notice.release_notes.feature_roadtrip_title': 'إضافة الرحلة البرية',
'system_notice.release_400.feature_studio_body': 'system_notice.release_notes.feature_roadtrip_body':
'تحوّل PDF الخاص بـ Journey إلى مصمّم ألبومات صور. يرتّب الألبوم حين تطلب منه، ثم يبتعد عن طريقك.', 'وضع الرحلة البرية يخطط القيادة نفسها: المسار، ومسافته، وساعات القيادة، ومحطات التوقف. إنها إضافة، تبقى معطَّلة حتى يفعّلها المسؤول.',
'system_notice.release_400.feature_vacay_title': 'Vacay يتعلّم الباقي', 'system_notice.release_notes.feature_dawarich_title': 'تكامل Dawarich',
'system_notice.release_400.feature_vacay_body': 'system_notice.release_notes.feature_dawarich_body':
'أنصاف الأيام، وأيام التعويض والمرونة، والعطل المدرسية على الشبكة — وسنة إجازات لا يلزم أن تبدأ في يناير.', 'البديل المستضاف ذاتيًا لـ Google Timeline، وصار بالإمكان الآن قراءته داخل TREK. يقرأ TREK، ويقرأ فقط. ولا يُكتب فيه أي شيء أبدًا.',
'system_notice.release_400.feature_places_title': 'الأماكن تعرّف عن نفسها، والملفات تنتقل', 'system_notice.release_notes.footnote': 'إلى جانب قائمة طويلة من التغييرات الأصغر في بقية أرجاء TREK.',
'system_notice.release_400.feature_places_body': 'system_notice.release_notes.notes_label': 'ملاحظات الإصدار',
'تُملأ الصور والوصف تلقائيًا قبل أن تحفظ المكان. ولم تعد ملفاتك المرفوعة مضطرة للبقاء على القرص الذي يعمل عليه TREK.', 'system_notice.release_notes.note_eyebrow': 'كلمة من صاحب المشروع',
'system_notice.release_400.footnote': 'system_notice.release_notes.note_title': 'أنتم السبب في أنني ما زلت أبني TREK.',
'وهذه أربعة منها فقط. يحمل 4.0.0 مئات التغييرات الأخرى، من Collections و Atlas إلى الخادم بأكمله تحتها.', 'system_notice.release_notes.note_body':
'system_notice.release_400.note_eyebrow': 'كلمة من صاحب المشروع', 'بدأ TREK كأداة صغيرة لرحلاتي الخاصة، كتبتها بعد العمل لأنني أردت طريقة أفضل لتخطيطها. ومنذ ذلك الحين لم يتوقف عن النمو. كل ما تستخدمه تقريبًا بُني في ساعات متأخرة من الليل، وفي عطل نهاية الأسبوع، وفي القطارات، إلى جانب عمل بدوام كامل، وكم من أمسية تساءلت فيها بيني وبين نفسي: هل سيفتحه أحد يومًا؟',
'system_notice.release_400.note_title': 'شكرًا لاستخدامك TREK.', 'system_notice.release_notes.promise_label': 'الوعد',
'system_notice.release_400.note_body': 'system_notice.release_notes.promise_lead': 'سيبقى TREK مجانيًا، إلى الأبد.',
'بدأ TREK كأداة صغيرة لرحلاتي الخاصة، كتبتها في وقت فراغي. وما زال كذلك: أمسيات، وعطل نهاية الأسبوع، والساعات المتبقية بجانب عمل بدوام كامل.\n\nلفترة كنت وحدي. لم يعد الأمر كذلك — تسعة عشر شخصًا أطلقوا هذا الإصدار، وآلاف منكم جاؤوا بنجوم ومشكلات وترجمات وطلبات دمج. أنا ممتن لكل جزء من ذلك.', 'system_notice.release_notes.promise_text': 'كل ميزة، وكل تحديث، للجميع. لا باقات مدفوعة، لا اشتراكات، لا شروط خفية.',
'system_notice.release_400.promise_label': 'الوعد', 'system_notice.release_notes.note_body_after':
'system_notice.release_400.promise_text': 'ثم فتحتموه. وخلال بضعة أشهر صرتم بالآلاف: نجوم، وبلاغات أخطاء، وترجمات إلى لغات لا أتحدثها، وطلبات دمج من أشخاص لم ألتقِ بهم قط. ما زلت أتفقد المستودع أول شيء كل صباح، وما زال الأمر لا يبدو حقيقيًا تمامًا.',
'الجانب مفتوح المصدر من TREK يبقى مجانيًا، إلى الأبد. لا باقات مدفوعة، لا اشتراكات، لا شروط خفية. أعدكم.', 'system_notice.release_notes.note_closing': 'شكرًا لوجودك هنا. مع تحياتي، Maurice.',
'system_notice.release_400.note_body_after': 'system_notice.release_notes.support_lead':
'استغرق 4.0.0 أسابيع من الليالي المتأخرة — تطبيق هاتف، ومصمّم ألبومات، وترحيل الخادم، معظمه كُتب بين منتصف الليل والثانية. ليست شكوى: أحب بناء هذا. إنها فقط الإجابة الصادقة عن كيف يخرج إصدار بهذا الحجم من مشروع في وقت الفراغ.', 'صحيح أن TREK مجاني وسيبقى كذلك دائمًا، لكن الخوادم والنطاقات والكثير من الليالي المتأخرة ليست مجانية.',
'system_notice.release_400.note_closing': 'شكرًا لوجودك هنا.', 'system_notice.release_notes.support_text':
'system_notice.release_400.note_signature': '— Maurice', 'إن كان TREK قد استحق مكانًا في رحلاتك، فاشترِ لي فنجان قهوة وساعد في أن يرى الإصدار القادم النور.',
'system_notice.release_400.support_text': 'system_notice.release_notes.cta_bmc': 'Buy me a coffee',
'الدعم هو ما يبقي هذا مستمرًا — الخوادم والنطاقات والليالي المتأخرة التي تتحول إلى إصدارات كهذا. إذا كان TREK يساوي شيئًا لك، ففنجان قهوة هو أقصر طريق لإبقائه مستمرًا.', 'system_notice.release_notes.cta_kofi': 'ادعمني على Ko-fi',
'system_notice.release_400.cta_bmc': 'Buy me a coffee',
'system_notice.release_400.cta_kofi': 'ادعمني على Ko-fi',
}; };
export default system_notice; export default system_notice;
+35 -36
View File
@@ -54,41 +54,40 @@ const system_notice: TranslationStrings = {
'system_notice.v3014_whitespace_collision.title': 'Ação necessária: conflito de conta de usuário', 'system_notice.v3014_whitespace_collision.title': 'Ação necessária: conflito de conta de usuário',
'system_notice.v3014_whitespace_collision.body': 'system_notice.v3014_whitespace_collision.body':
'A atualização 3.0.14 detectou um ou mais conflitos de nome de usuário ou e-mail causados por espaços em branco no início ou fim dos valores armazenados. As contas afetadas foram renomeadas automaticamente. Verifique os logs do servidor por linhas começando com **[migration] WHITESPACE COLLISION** para identificar quais contas precisam de revisão.', 'A atualização 3.0.14 detectou um ou mais conflitos de nome de usuário ou e-mail causados por espaços em branco no início ou fim dos valores armazenados. As contas afetadas foram renomeadas automaticamente. Verifique os logs do servidor por linhas começando com **[migration] WHITESPACE COLLISION** para identificar quais contas precisam de revisão.',
// 4.0.0 release modal — the release on the left, the note from the maintainer on the right // The release modal. One stable set of keys: each big release swaps the copy in place.
'system_notice.release_400.eyebrow': 'Atualização instalada', 'system_notice.release_notes.eyebrow': 'Atualização instalada',
'system_notice.release_400.tag': 'Versão', 'system_notice.release_notes.headline': 'Três coisas que o TREK agora faz sozinho.',
'system_notice.release_400.headline': 'A maior versão que o TREK já teve.', 'system_notice.release_notes.intro':
'system_notice.release_400.intro': 'Uma API de lugares própria, viagens de carro planejadas de ponta a ponta e o seu histórico de localização de volta nas suas mãos.',
'O TREK ganha um celular e um livro. Dezenove pessoas escreveram esta — e com ela foram uns cento e cinquenta bugs relatados.', 'system_notice.release_notes.features_label': 'Os destaques',
'system_notice.release_400.feature_mobile_title': 'TREK no celular', 'system_notice.release_notes.features_aside': 'E não é só isso',
'system_notice.release_400.feature_mobile_body': 'system_notice.release_notes.feature_places_title': 'TREK Places API',
'Tudo abaixo de 768px agora é uma interface própria — um dock de vidro, seus próprios painéis, seu próprio planejador. Abra o TREK no celular.', 'system_notice.release_notes.feature_places_body':
'system_notice.release_400.feature_studio_title': 'TREK Studio', 'O primeiro planejador de viagens open source que hospeda a própria API de lugares. 73,6 milhões de lugares, reconstruídos todo mês. Sem chave, sem cota.',
'system_notice.release_400.feature_studio_badge': 'Beta', 'system_notice.release_notes.feature_roadtrip_title': 'Addon Viagem de carro',
'system_notice.release_400.feature_studio_body': 'system_notice.release_notes.feature_roadtrip_body':
'O PDF do Journey virou um designer de álbuns de fotos. Ele monta o álbum quando você pede e depois sai do caminho.', 'O modo viagem de carro planeja o próprio trajeto: a rota, a distância, as horas de direção e as paradas. É um addon, desligado até que um admin o ative.',
'system_notice.release_400.feature_vacay_title': 'Vacay aprende o resto', 'system_notice.release_notes.feature_dawarich_title': 'Integração Dawarich',
'system_notice.release_400.feature_vacay_body': 'system_notice.release_notes.feature_dawarich_body':
'Meios dias, banco de horas e dias flexíveis, férias escolares na grade — e um ano de férias que não precisa começar em janeiro.', 'A alternativa self-hosted ao Google Timeline, agora visível dentro do TREK. O TREK lê, e apenas lê. Nada nunca é gravado de volta.',
'system_notice.release_400.feature_places_title': 'Lugares que se mostram, arquivos que saem', 'system_notice.release_notes.footnote': 'E ainda uma longa lista de mudanças menores em todo o resto do TREK.',
'system_notice.release_400.feature_places_body': 'system_notice.release_notes.notes_label': 'Notas da versão',
'Fotos e descrição se preenchem sozinhas antes de você salvar um lugar. E seus uploads não precisam mais viver no disco onde o TREK roda.', 'system_notice.release_notes.note_eyebrow': 'Uma nota do mantenedor',
'system_notice.release_400.footnote': 'system_notice.release_notes.note_title': 'Vocês são a razão de eu continuar construindo o TREK.',
'E estes são quatro deles. A 4.0.0 traz centenas de outras mudanças, de Collections e Atlas até todo o servidor por baixo.', 'system_notice.release_notes.note_body':
'system_notice.release_400.note_eyebrow': 'Uma nota do mantenedor', 'O TREK começou como uma ferramentinha para as minhas próprias viagens, escrita depois do trabalho porque eu queria um jeito melhor de planejá-las. E nunca parou de crescer de verdade. Quase tudo o que vocês usam foi construído tarde da noite, nos fins de semana, em trens, ao lado de um trabalho em tempo integral, e foram muitas as noites em que me perguntei, em silêncio, se alguém lá fora algum dia chegaria a abri-lo.',
'system_notice.release_400.note_title': 'Obrigado por usar o TREK.', 'system_notice.release_notes.promise_label': 'A promessa',
'system_notice.release_400.note_body': 'system_notice.release_notes.promise_lead': 'O TREK continua gratuito, para sempre.',
'O TREK começou como uma ferramentinha para as minhas próprias viagens, escrita no tempo livre. E continua sendo: noites, fins de semana, as horas ao lado de um trabalho em tempo integral.\n\nPor um tempo era só eu. Não mais — dezenove pessoas entregaram esta versão, e milhares de pessoas chegaram com estrelas, issues, traduções e pull requests. Sou grato por cada parte disso.', 'system_notice.release_notes.promise_text':
'system_notice.release_400.promise_label': 'A promessa', 'Cada recurso, cada atualização, para todo mundo. Sem planos pagos, sem assinaturas, sem pegadinhas.',
'system_notice.release_400.promise_text': 'system_notice.release_notes.note_body_after':
'O lado open source do TREK continua gratuito, para sempre. Sem planos pagos, sem assinaturas, sem pegadinhas. Prometido.', 'E aí vocês abriram. Em poucos meses eram milhares: estrelas, relatos de bugs, traduções para idiomas que eu não falo, pull requests de pessoas que nunca conheci. Até hoje a primeira coisa que faço toda manhã é olhar o repositório, e ainda não parece totalmente real.',
'system_notice.release_400.note_body_after': 'system_notice.release_notes.note_closing': 'Obrigado por estarem aqui. Um abraço, Maurice.',
'A 4.0.0 levou semanas de noites longas — um app de celular, um designer de álbuns, uma migração de servidor, quase tudo escrito entre meia-noite e duas. Não é reclamação: eu amo construir isso. É só a resposta honesta de como uma versão desse tamanho sai de um projeto de tempo livre.', 'system_notice.release_notes.support_lead':
'system_notice.release_400.note_closing': 'Obrigado por estar aqui.', 'O TREK é gratuito e sempre vai ser, mas servidores, domínios e muitas noites em claro não são.',
'system_notice.release_400.note_signature': '— Maurice', 'system_notice.release_notes.support_text':
'system_notice.release_400.support_text': 'Se o TREK ganhou um lugar nas suas viagens, me pague um café e ajude a fazer a próxima versão acontecer.',
'O apoio é o que mantém isso de pé — servidores, domínios e as noites longas que viram versões como esta. Se o TREK vale algo para você, um café é o jeito mais direto de manter isso vivo.', 'system_notice.release_notes.cta_bmc': 'Buy me a coffee',
'system_notice.release_400.cta_bmc': 'Buy me a coffee', 'system_notice.release_notes.cta_kofi': 'Apoiar no Ko-fi',
'system_notice.release_400.cta_kofi': 'Apoiar no Ko-fi',
}; };
export default system_notice; export default system_notice;
+34 -35
View File
@@ -55,40 +55,39 @@ const system_notice: TranslationStrings = {
'system_notice.thank_you_support.highlight_community': 'Construït conjuntament amb la comunitat', 'system_notice.thank_you_support.highlight_community': 'Construït conjuntament amb la comunitat',
'system_notice.thank_you_support.cta_bmc': 'Buy Me a Coffee', 'system_notice.thank_you_support.cta_bmc': 'Buy Me a Coffee',
'system_notice.thank_you_support.cta_kofi': 'Dona suport a Ko-fi', 'system_notice.thank_you_support.cta_kofi': 'Dona suport a Ko-fi',
'system_notice.release_400.eyebrow': 'Actualització instal·lada', 'system_notice.release_notes.eyebrow': 'Actualització instal·lada',
'system_notice.release_400.tag': 'Versió', 'system_notice.release_notes.headline': 'Tres coses que TREK ja fa tot sol.',
'system_notice.release_400.headline': 'La versió més gran que TREK ha tingut mai.', 'system_notice.release_notes.intro':
'system_notice.release_400.intro': "La seva pròpia API de llocs, viatges per carretera planificats de principi a fi i el teu historial d'ubicacions de nou a les teves mans.",
'TREK guanya un telèfon, i un llibre. Dinou persones han escrit aquesta versió — i uns cent cinquanta errors reportats han desaparegut pel camí.', 'system_notice.release_notes.features_label': 'Els protagonistes',
'system_notice.release_400.feature_mobile_title': 'TREK es fa mòbil', 'system_notice.release_notes.features_aside': 'I això no és tot',
'system_notice.release_400.feature_mobile_body': 'system_notice.release_notes.feature_places_title': 'TREK Places API',
'Tot el que hi ha per sota de 768px té ara la seva pròpia interfície — un dock de vidre, els seus fulls, el seu planificador. Obre TREK al telèfon.', 'system_notice.release_notes.feature_places_body':
'system_notice.release_400.feature_studio_title': 'TREK Studio', 'El primer planificador de viatges de codi obert que allotja la seva pròpia API de llocs. 73,6 milions de llocs, reconstruïts cada mes. Sense clau, sense quota.',
'system_notice.release_400.feature_studio_badge': 'Beta', 'system_notice.release_notes.feature_roadtrip_title': 'Complement Roadtrip',
'system_notice.release_400.feature_studio_body': 'system_notice.release_notes.feature_roadtrip_body':
"El PDF de Journey s'ha convertit en un dissenyador de llibres de fotos. Compon el llibre quan l'hi demanes i després s'aparta.", "El mode viatge per carretera també planifica el trajecte en cotxe: la ruta, la distància, les hores al volant i les parades. És un complement, desactivat fins que un admin l'activi.",
'system_notice.release_400.feature_vacay_title': 'Vacay aprèn la resta', 'system_notice.release_notes.feature_dawarich_title': 'Integració amb Dawarich',
'system_notice.release_400.feature_vacay_body': 'system_notice.release_notes.feature_dawarich_body':
'Mitjos dies, dies de compensació i flexibles, vacances escolars a la graella — i un any de vacances que no ha de començar al gener.', "L'alternativa autoallotjada a Google Timeline, ara llegible des de TREK. TREK llegeix, i només llegeix. Mai no s'escriu res a Dawarich.",
'system_notice.release_400.feature_places_title': 'Els llocs es mostren, els fitxers marxen', 'system_notice.release_notes.footnote': 'I una llarga llista de canvis més petits a la resta de TREK.',
'system_notice.release_400.feature_places_body': 'system_notice.release_notes.notes_label': 'Notes de la versió',
"Les imatges i una descripció s'omplen soles abans que desis un lloc. I les teves pujades ja no han de viure al disc on s'executa TREK.", 'system_notice.release_notes.note_eyebrow': 'Una nota del mantenidor',
'system_notice.release_400.footnote': 'system_notice.release_notes.note_title': 'Sou el motiu pel qual continuo construint TREK.',
'I aquestes en són quatre. La 4.0.0 porta diversos centenars de canvis més, des de Collections i Atlas fins a tot el servidor de sota.', 'system_notice.release_notes.note_body':
'system_notice.release_400.note_eyebrow': 'Una nota del mantenidor', "TREK va néixer com una petita eina per als meus propis viatges, escrita després de la feina perquè volia una manera millor de planificar-los. En realitat, mai no ha deixat de créixer. Gairebé tot ho he construït a altes hores de la nit, els caps de setmana, als trens, al costat d'una feina a jornada completa, i més d'una vegada em vaig preguntar en silenci si algú, en algun lloc, l'obriria mai.",
'system_notice.release_400.note_title': 'Gràcies per utilitzar TREK.', 'system_notice.release_notes.promise_label': 'La promesa',
'system_notice.release_400.note_body': 'system_notice.release_notes.promise_lead': 'TREK continuarà sent gratuït, per sempre.',
"TREK va començar com una petita eina per als meus propis viatges, escrita al meu temps lliure. Encara ho és: vespres, caps de setmana, les hores al costat d'una feina a jornada completa.\n\nDurant un temps només hi era jo. Ja no — dinou persones han fet aquesta versió, i milers de vosaltres heu arribat amb estrelles, issues, traduccions i pull requests. Estic agraït per tot plegat.", 'system_notice.release_notes.promise_text':
'system_notice.release_400.promise_label': 'La promesa', 'Cada funcionalitat, cada actualització, per a tothom. Sense nivells de pagament, sense subscripcions, sense lletra petita.',
'system_notice.release_400.promise_text': 'system_notice.release_notes.note_body_after':
'La part de codi obert de TREK segueix sent gratuïta, per sempre. Sense nivells de pagament, sense subscripcions, sense lletra petita. Promès.', "I llavors el vau obrir. En pocs mesos éreu milers: estrelles, informes d'errors, traduccions a llengües que no parlo, pull requests de gent que no he conegut mai. El primer que faig cada matí continua sent mirar el repositori, i encara em costa creure-m'ho.",
'system_notice.release_400.note_body_after': 'system_notice.release_notes.note_closing': 'Gràcies per ser aquí. Una abraçada, Maurice.',
"La 4.0.0 ha costat setmanes de nits llargues — una app de mòbil, un dissenyador de llibres, una migració del servidor, la major part escrita entre mitjanit i les dues. No és una queixa: m'encanta construir això. És només la resposta honesta a com surt una versió d'aquesta mida d'un projecte de temps lliure.", 'system_notice.release_notes.support_lead':
'system_notice.release_400.note_closing': 'Gràcies per ser aquí.', 'TREK és gratuït i ho serà sempre, però els servidors, els dominis i tantes nits llargues no ho són.',
'system_notice.release_400.note_signature': '— Maurice', 'system_notice.release_notes.support_text':
'system_notice.release_400.support_text': "Si s'ha guanyat un lloc als teus viatges, convida'm a un cafè i ajuda a fer que arribi la propera versió.",
'El suport és el que fa que això funcioni — servidors, dominis i les nits llargues que es converteixen en versions com aquesta. Si TREK val alguna cosa per a tu, un cafè és la manera més directa de mantenir-ho en marxa.', 'system_notice.release_notes.cta_bmc': 'Buy me a coffee',
'system_notice.release_400.cta_bmc': 'Buy me a coffee', 'system_notice.release_notes.cta_kofi': 'Dona suport a Ko-fi',
'system_notice.release_400.cta_kofi': 'Dona suport a Ko-fi',
}; };
export default system_notice; export default system_notice;
+35 -36
View File
@@ -54,41 +54,40 @@ const system_notice: TranslationStrings = {
'system_notice.v3014_whitespace_collision.title': 'Vyžadována akce: konflikt uživatelského účtu', 'system_notice.v3014_whitespace_collision.title': 'Vyžadována akce: konflikt uživatelského účtu',
'system_notice.v3014_whitespace_collision.body': 'system_notice.v3014_whitespace_collision.body':
'Aktualizace 3.0.14 zjistila jeden nebo více konfliktů uživatelského jména nebo e-mailu způsobených mezerami na začátku nebo konci uložených hodnot. Dotčené účty byly automaticky přejmenovány. Zkontrolujte protokoly serveru na řádky začínající **[migration] WHITESPACE COLLISION** a zjistěte, které účty vyžadují kontrolu.', 'Aktualizace 3.0.14 zjistila jeden nebo více konfliktů uživatelského jména nebo e-mailu způsobených mezerami na začátku nebo konci uložených hodnot. Dotčené účty byly automaticky přejmenovány. Zkontrolujte protokoly serveru na řádky začínající **[migration] WHITESPACE COLLISION** a zjistěte, které účty vyžadují kontrolu.',
// 4.0.0 release modal — the release on the left, the note from the maintainer on the right // The release modal. One stable set of keys: each big release swaps the copy in place.
'system_notice.release_400.eyebrow': 'Aktualizace nainstalována', 'system_notice.release_notes.eyebrow': 'Aktualizace nainstalována',
'system_notice.release_400.tag': 'Vydání', 'system_notice.release_notes.headline': 'Tři věci, které TREK teď zvládne sám.',
'system_notice.release_400.headline': 'Největší vydání, jaké kdy TREK měl.', 'system_notice.release_notes.intro':
'system_notice.release_400.intro': 'Vlastní API pro místa, cesty autem naplánované od začátku do konce a vaše historie polohy opět ve vašich rukou.',
'TREK dostává telefon a knihu. Tohle vydání psalo devatenáct lidí — a šlo s ním asi sto padesát nahlášených chyb.', 'system_notice.release_notes.features_label': 'Hlavní novinky',
'system_notice.release_400.feature_mobile_title': 'TREK jde do mobilu', 'system_notice.release_notes.features_aside': 'Zdaleka ne všechno',
'system_notice.release_400.feature_mobile_body': 'system_notice.release_notes.feature_places_title': 'TREK Places API',
'Všechno pod 768px je teď vlastní rozhraní — skleněný dok, vlastní panely, vlastní plánovač cesty. Otevřete TREK v telefonu.', 'system_notice.release_notes.feature_places_body':
'system_notice.release_400.feature_studio_title': 'TREK Studio', 'První open source plánovač cest, který provozuje vlastní API pro místa. 73,6 milionu míst, každý měsíc nově sestavených. Žádný klíč, žádná kvóta.',
'system_notice.release_400.feature_studio_badge': 'Beta', 'system_notice.release_notes.feature_roadtrip_title': 'Doplněk Cesta autem',
'system_notice.release_400.feature_studio_body': 'system_notice.release_notes.feature_roadtrip_body':
'Z PDF v Journey se stal návrhář fotoknihy. Rozvrhne knihu, když si řeknete, a pak jde stranou.', 'Režim Cesta autem naplánuje i samotnou jízdu: trasu, vzdálenost, hodiny za volantem i zastávky. Jde o doplněk, který zůstává vypnutý, dokud ho nezapne správce.',
'system_notice.release_400.feature_vacay_title': 'Vacay umí i zbytek', 'system_notice.release_notes.feature_dawarich_title': 'Integrace Dawarich',
'system_notice.release_400.feature_vacay_body': 'system_notice.release_notes.feature_dawarich_body':
'Půldny, náhradní volno a flexi dny, školní prázdniny v mřížce — a rok dovolené, který nemusí začínat v lednu.', 'Self-hosted odpověď na Google Timeline, teď čitelná přímo v TREK. TREK čte, a jen čte. Nic se nikdy nezapisuje zpět.',
'system_notice.release_400.feature_places_title': 'Místa se ukážou, soubory se odstěhují', 'system_notice.release_notes.footnote': 'A k tomu dlouhý seznam menších změn napříč zbytkem TREK.',
'system_notice.release_400.feature_places_body': 'system_notice.release_notes.notes_label': 'Poznámky k vydání',
'Obrázky a popis se doplní samy, ještě než místo uložíte. A nahrané soubory už nemusí ležet na disku, kde běží TREK.', 'system_notice.release_notes.note_eyebrow': 'Slovo od autora',
'system_notice.release_400.footnote': 'system_notice.release_notes.note_title': 'Vy jste důvod, proč na TREK pořád pracuji.',
'A tohle jsou čtyři z nich. 4.0.0 nese několik stovek dalších změn, od Collections a Atlas až po celý server pod nimi.', 'system_notice.release_notes.note_body':
'system_notice.release_400.note_eyebrow': 'Slovo od autora', 'TREK začal jako malý nástroj pro mé vlastní cesty, psaný po práci, protože jsem je chtěl plánovat lépe. Vlastně nikdy nepřestal růst. Skoro všechno, co používáte, vzniklo pozdě v noci, o víkendech, ve vlacích, vedle práce na plný úvazek, a bylo spoustu večerů, kdy jsem se potichu ptal, jestli ho tam venku vůbec někdy někdo otevře.',
'system_notice.release_400.note_title': 'Děkuji, že používáte TREK.', 'system_notice.release_notes.promise_label': 'Slib',
'system_notice.release_400.note_body': 'system_notice.release_notes.promise_lead': 'TREK zůstane zdarma, navždy.',
'TREK začal jako malý nástroj pro mé vlastní cesty, psaný ve volném čase. Pořád jím je: večery, víkendy, hodiny vedle práce na plný úvazek.\n\nChvíli jsem na to byl sám. Už ne — tohle vydání dotáhlo devatenáct lidí a tisíce z vás přišly s hvězdičkami, issues, překlady a pull requesty. Jsem vděčný za každý kousek.', 'system_notice.release_notes.promise_text':
'system_notice.release_400.promise_label': 'Slib', 'Každá funkce, každá aktualizace, pro všechny. Žádné placené verze, žádná předplatná, žádné háčky.',
'system_notice.release_400.promise_text': 'system_notice.release_notes.note_body_after':
'Open source část TREK zůstane zdarma, navždy. Žádné placené verze, žádná předplatná, žádné háčky. Slibuji.', 'A pak jste ho otevřeli. Během pár měsíců vás byly tisíce: hvězdičky, hlášení chyb, překlady do jazyků, kterými nemluvím, pull requesty od lidí, které jsem nikdy nepotkal. Každé ráno se pořád nejdřív podívám do repozitáře a pořád mi to nepřijde úplně skutečné.',
'system_notice.release_400.note_body_after': 'system_notice.release_notes.note_closing': 'Děkuji, že jste tady. Váš Maurice',
'4.0.0 stálo týdny pozdních nocí — aplikace do telefonu, návrhář knih, migrace serveru, většina psaná mezi půlnocí a druhou. Není to stížnost: baví mě to stavět. Je to jen upřímná odpověď na to, jak z projektu ve volném čase vznikne takhle velké vydání.', 'system_notice.release_notes.support_lead':
'system_notice.release_400.note_closing': 'Děkuji, že jste tady.', 'TREK je a vždycky bude zdarma, ale servery, domény a spousta pozdních nocí zdarma nejsou.',
'system_notice.release_400.note_signature': '— Maurice', 'system_notice.release_notes.support_text':
'system_notice.release_400.support_text': 'Pokud si TREK získal místo na vašich cestách, kupte mi kávu a pomozte, aby přišlo i další vydání.',
'Podpora je to, co tohle drží v chodu — servery, domény a pozdní noci, ze kterých vznikají vydání jako tohle. Pokud pro vás TREK něco znamená, káva je nejpřímější způsob, jak ho udržet v běhu.', 'system_notice.release_notes.cta_bmc': 'Buy me a coffee',
'system_notice.release_400.cta_bmc': 'Buy me a coffee', 'system_notice.release_notes.cta_kofi': 'Podpořit na Ko-fi',
'system_notice.release_400.cta_kofi': 'Podpořit na Ko-fi',
}; };
export default system_notice; export default system_notice;
+35 -36
View File
@@ -55,41 +55,40 @@ const system_notice: TranslationStrings = {
'system_notice.v3014_whitespace_collision.title': 'Aktion erforderlich: Benutzerkontokonflikt', 'system_notice.v3014_whitespace_collision.title': 'Aktion erforderlich: Benutzerkontokonflikt',
'system_notice.v3014_whitespace_collision.body': 'system_notice.v3014_whitespace_collision.body':
'Das 3.0.14-Upgrade hat einen oder mehrere Konflikte bei Benutzernamen oder E-Mail-Adressen festgestellt, die durch führende oder nachgestellte Leerzeichen in gespeicherten Konten verursacht wurden. Betroffene Konten wurden automatisch umbenannt. Prüfe die Serverprotokolle auf Zeilen, die mit **[migration] WHITESPACE COLLISION** beginnen, um die betroffenen Konten zu identifizieren.', 'Das 3.0.14-Upgrade hat einen oder mehrere Konflikte bei Benutzernamen oder E-Mail-Adressen festgestellt, die durch führende oder nachgestellte Leerzeichen in gespeicherten Konten verursacht wurden. Betroffene Konten wurden automatisch umbenannt. Prüfe die Serverprotokolle auf Zeilen, die mit **[migration] WHITESPACE COLLISION** beginnen, um die betroffenen Konten zu identifizieren.',
// 4.0.0-Release-Modal — links das Release, rechts das Wort vom Maintainer // The release modal. One stable set of keys: each big release swaps the copy in place.
'system_notice.release_400.eyebrow': 'Update installiert', 'system_notice.release_notes.eyebrow': 'Update installiert',
'system_notice.release_400.tag': 'Release', 'system_notice.release_notes.headline': 'Drei Dinge, die TREK jetzt selbst erledigt.',
'system_notice.release_400.headline': 'Das größte Release, das TREK je hatte.', 'system_notice.release_notes.intro':
'system_notice.release_400.intro': 'Eine eigene API für Orte, Roadtrips von Anfang bis Ende geplant und dein Standortverlauf wieder in deiner Hand.',
'TREK bekommt ein Handy und ein Buch. Neunzehn Leute haben daran geschrieben — und rund hundertfünfzig gemeldete Bugs sind mitgekommen.', 'system_notice.release_notes.features_label': 'Die Highlights',
'system_notice.release_400.feature_mobile_title': 'TREK wird mobil', 'system_notice.release_notes.features_aside': 'Längst nicht alles',
'system_notice.release_400.feature_mobile_body': 'system_notice.release_notes.feature_places_title': 'TREK Places API',
'Alles unter 768px ist jetzt eine eigene Oberfläche — ein Glas-Dock, eigene Sheets, ein eigener Trip-Planer. Öffne TREK auf deinem Handy.', 'system_notice.release_notes.feature_places_body':
'system_notice.release_400.feature_studio_title': 'TREK Studio', 'Der erste Open-Source-Reiseplaner, der seine eigene API für Orte betreibt. 73,6 Millionen Orte, jeden Monat neu aufgebaut. Kein Schlüssel, kein Kontingent.',
'system_notice.release_400.feature_studio_badge': 'Beta', 'system_notice.release_notes.feature_roadtrip_title': 'Roadtrip-Addon',
'system_notice.release_400.feature_studio_body': 'system_notice.release_notes.feature_roadtrip_body':
'Aus dem Journey-PDF wurde ein Fotobuch-Designer. Er setzt das Buch, wenn du ihn darum bittest, und hält sich danach raus.', 'Der Roadtrip-Modus plant die Fahrt selbst: die Route, ihre Länge, die Fahrzeit und die Stopps. Ein Addon, das aus bleibt, bis ein Admin es einschaltet.',
'system_notice.release_400.feature_vacay_title': 'Vacay lernt den Rest', 'system_notice.release_notes.feature_dawarich_title': 'Dawarich-Integration',
'system_notice.release_400.feature_vacay_body': 'system_notice.release_notes.feature_dawarich_body':
'Halbe Tage, Überstunden- und Gleittage, Schulferien im Raster — und ein Urlaubsjahr, das nicht im Januar anfangen muss.', 'Die selbst gehostete Antwort auf Google Timeline, jetzt direkt in TREK lesbar. TREK liest, und nur das. Zurückgeschrieben wird nie etwas.',
'system_notice.release_400.feature_places_title': 'Orte zeigen sich, Dateien ziehen aus', 'system_notice.release_notes.footnote': 'Dazu kommt eine lange Liste kleinerer Änderungen überall sonst in TREK.',
'system_notice.release_400.feature_places_body': 'system_notice.release_notes.notes_label': 'Release Notes',
'Bilder und eine Beschreibung füllen sich von selbst, bevor du einen Ort speicherst. Und deine Uploads müssen nicht mehr auf der Platte liegen, auf der TREK läuft.', 'system_notice.release_notes.note_eyebrow': 'Ein Wort vom Maintainer',
'system_notice.release_400.footnote': 'system_notice.release_notes.note_title': 'Du bist der Grund, warum ich TREK weiterbaue.',
'Und das sind vier davon. 4.0.0 bringt mehrere hundert weitere Änderungen mit, von Collections und Atlas bis zum ganzen Server darunter.', 'system_notice.release_notes.note_body':
'system_notice.release_400.note_eyebrow': 'Ein Wort vom Maintainer', 'TREK hat als kleines Tool für meine eigenen Reisen angefangen, geschrieben nach Feierabend, weil ich sie besser planen wollte. Aufgehört zu wachsen hat es eigentlich nie. Fast alles, was du nutzt, ist spät in der Nacht entstanden, am Wochenende, im Zug, neben einem Vollzeitjob, und an so manchem Abend habe ich mich still gefragt, ob es da draußen überhaupt jemals jemand öffnen würde.',
'system_notice.release_400.note_title': 'Danke, dass du TREK nutzt.', 'system_notice.release_notes.promise_label': 'Das Versprechen',
'system_notice.release_400.note_body': 'system_notice.release_notes.promise_lead': 'TREK bleibt kostenlos, für immer.',
'TREK hat als kleines Tool für meine eigenen Reisen angefangen, geschrieben in meiner Freizeit. Das ist es immer noch: Abende, Wochenenden, die Stunden neben einem Vollzeitjob.\n\nEine Weile war ich allein damit. Jetzt nicht mehr — neunzehn Leute haben dieses Release gebaut, und Tausende von euch kamen dazu, mit Sternen, Issues, Übersetzungen und Pull Requests. Ich bin für jedes Stück davon dankbar.', 'system_notice.release_notes.promise_text':
'system_notice.release_400.promise_label': 'Das Versprechen', 'Jede Funktion, jedes Update, für alle. Keine Paid Tiers, keine Abos, kein Haken.',
'system_notice.release_400.promise_text': 'system_notice.release_notes.note_body_after':
'Die Open-Source-Seite von TREK bleibt kostenlos, für immer. Keine Paid Tiers, keine Abos, kein Haken. Versprochen.', 'Dann kamt ihr. Innerhalb weniger Monate wart ihr Tausende: Sterne, Bug-Reports, Übersetzungen in Sprachen, die ich nicht spreche, Pull Requests von Leuten, die ich nie getroffen habe. Ich schaue noch immer jeden Morgen als Erstes ins Repository, und so richtig real fühlt es sich bis heute nicht an.',
'system_notice.release_400.note_body_after': 'system_notice.release_notes.note_closing': 'Danke, dass du dabei bist. Viele Grüße, Maurice.',
'4.0.0 hat Wochen an späten Nächten gekostet — eine Handy-App, ein Buch-Designer, eine Server-Migration, das meiste zwischen Mitternacht und zwei geschrieben. Keine Klage: Ich baue das gern. Es ist nur die ehrliche Antwort darauf, wie ein Release dieser Größe aus einem Freizeitprojekt kommt.', 'system_notice.release_notes.support_lead':
'system_notice.release_400.note_closing': 'Danke, dass du dabei bist.', 'TREK ist kostenlos und wird es immer bleiben, aber Server, Domains und viele späte Nächte sind es nicht.',
'system_notice.release_400.note_signature': '— Maurice', 'system_notice.release_notes.support_text':
'system_notice.release_400.support_text': 'Wenn TREK sich einen Platz auf deinen Reisen verdient hat, spendier mir einen Kaffee und hilf mit, dass auch das nächste Release kommt.',
'Unterstützung ist das, was das hier am Laufen hält — Server, Domains und die späten Nächte, aus denen Releases wie dieses werden. Wenn TREK dir etwas wert ist, ist ein Kaffee der direkteste Weg, es weiterlaufen zu lassen.', 'system_notice.release_notes.cta_bmc': 'Buy me a coffee',
'system_notice.release_400.cta_bmc': 'Buy me a coffee', 'system_notice.release_notes.cta_kofi': 'Ko-fi unterstützen',
'system_notice.release_400.cta_kofi': 'Ko-fi unterstützen',
}; };
export default system_notice; export default system_notice;
+35 -36
View File
@@ -50,42 +50,41 @@ const system_notice: TranslationStrings = {
'system_notice.thank_you_support.highlight_community': 'Built together with the community', 'system_notice.thank_you_support.highlight_community': 'Built together with the community',
'system_notice.thank_you_support.cta_bmc': 'Buy Me a Coffee', 'system_notice.thank_you_support.cta_bmc': 'Buy Me a Coffee',
'system_notice.thank_you_support.cta_kofi': 'Support on Ko-fi', 'system_notice.thank_you_support.cta_kofi': 'Support on Ko-fi',
// 4.0.0 release modal — the release on the left, the note from the maintainer on the right // The release modal. One stable set of keys: each big release swaps the copy in place.
'system_notice.release_400.eyebrow': 'Update installed', 'system_notice.release_notes.eyebrow': 'Update installed',
'system_notice.release_400.tag': 'Release', 'system_notice.release_notes.headline': 'Three things TREK now does on its own.',
'system_notice.release_400.headline': 'The biggest release TREK has ever had.', 'system_notice.release_notes.intro':
'system_notice.release_400.intro': 'Its own place API, road trips planned end to end, and your location history back in your hands.',
'TREK gets a phone, and a book. Nineteen people wrote this one — and about a hundred and fifty reported bugs went with it.', 'system_notice.release_notes.features_label': 'The headliners',
'system_notice.release_400.feature_mobile_title': 'TREK goes mobile', 'system_notice.release_notes.features_aside': 'Far from everything',
'system_notice.release_400.feature_mobile_body': 'system_notice.release_notes.feature_places_title': 'TREK Places API',
'Everything under 768px is its own interface now — a glass dock, its own sheets, its own trip planner. Open TREK on your phone.', 'system_notice.release_notes.feature_places_body':
'system_notice.release_400.feature_studio_title': 'TREK Studio', 'The first open source travel planner that hosts its own place API. 73.6 million places, rebuilt monthly. No key, no quota.',
'system_notice.release_400.feature_studio_badge': 'Beta', 'system_notice.release_notes.feature_roadtrip_title': 'Roadtrip Addon',
'system_notice.release_400.feature_studio_body': 'system_notice.release_notes.feature_roadtrip_body':
'The Journey PDF became a photo book designer. It lays the book out when you ask it to, then gets out of the way.', 'Road trip mode plans the drive itself: the route, its distance, its hours and its stops. An addon, off until an admin turns it on.',
'system_notice.release_400.feature_vacay_title': 'Vacay learns the rest', 'system_notice.release_notes.feature_dawarich_title': 'Dawarich Integration',
'system_notice.release_400.feature_vacay_body': 'system_notice.release_notes.feature_dawarich_body':
'Half days, comp and flex days, school holidays on the grid — and a leave year that does not have to start in January.', 'The self-hosted answer to Google Timeline, now readable inside TREK. TREK reads, and only reads. Nothing is ever written back.',
'system_notice.release_400.feature_places_title': 'Places show themselves, files move out', 'system_notice.release_notes.footnote': 'Plus a long list of smaller changes across the rest of TREK.',
'system_notice.release_400.feature_places_body': 'system_notice.release_notes.notes_label': 'Release notes',
'Pictures and a description fill themselves in before you save a place. And your uploads no longer have to live on the disk TREK runs on.', 'system_notice.release_notes.note_eyebrow': 'A note from the maintainer',
'system_notice.release_400.footnote': 'system_notice.release_notes.note_title': 'You are the reason I keep building TREK.',
'And these are four of them. 4.0.0 carries several hundred further changes, from Collections and Atlas to the whole server underneath.', 'system_notice.release_notes.note_body':
'system_notice.release_400.note_eyebrow': 'A note from the maintainer', 'TREK began as a small tool for my own trips, written after work because I wanted a better way to plan them. It never really stopped growing. Almost everything you use was built late at night, on weekends, on trains, next to a full-time job, and there were plenty of evenings I quietly wondered whether anyone out there would ever open it.',
'system_notice.release_400.note_title': 'Thank you for using TREK.', 'system_notice.release_notes.promise_label': 'The promise',
'system_notice.release_400.note_body': 'system_notice.release_notes.promise_lead': 'TREK stays free, forever.',
'TREK started as a little tool for my own trips, written in my spare time. It still is: evenings, weekends, the hours next to a full-time job.\n\nFor a while it was only me. Not anymore — nineteen people shipped this release, and thousands of you arrived with stars, issues, translations and pull requests. I am grateful for every part of it.', 'system_notice.release_notes.promise_text':
'system_notice.release_400.promise_label': 'The promise', 'Every feature, every update, for everyone. No paid tiers, no subscriptions, no catch.',
'system_notice.release_400.promise_text': 'system_notice.release_notes.note_body_after':
'The open-source side of TREK stays free, forever. No paid tiers, no subscriptions, no catch. Promised.', 'Then you did. Within a few months there were thousands of you: stars, bug reports, translations into languages I do not speak, pull requests from people I have never met. I still check the repository first thing every morning, and it still does not quite feel real.',
'system_notice.release_400.note_body_after': 'system_notice.release_notes.note_closing': 'Thank you for being here, from Maurice.',
'4.0.0 took weeks of late nights — a phone app, a book designer, a server migration, most of it written between midnight and two. Not a complaint: I love building this. It is just the honest answer to how a release this size comes out of a spare-time project.', 'system_notice.release_notes.support_lead':
'system_notice.release_400.note_closing': 'Thank you for being here.', 'TREK is free and always will be, but servers, domains and a lot of late nights are not.',
'system_notice.release_400.note_signature': '— Maurice', 'system_notice.release_notes.support_text':
'system_notice.release_400.support_text': 'If it has earned a place in your trips, buy me a coffee and help keep the next release coming.',
'Support is what keeps this running — servers, domains, and the late nights that turn into releases like this one. If TREK is worth something to you, a coffee is the most direct way to keep it going.', 'system_notice.release_notes.cta_bmc': 'Buy me a coffee',
'system_notice.release_400.cta_bmc': 'Buy me a coffee', 'system_notice.release_notes.cta_kofi': 'Support on Ko-fi',
'system_notice.release_400.cta_kofi': 'Support on Ko-fi',
'system_notice.pager.prev': 'Previous notice', 'system_notice.pager.prev': 'Previous notice',
'system_notice.pager.next': 'Next notice', 'system_notice.pager.next': 'Next notice',
'system_notice.pager.counter': '{current} / {total}', 'system_notice.pager.counter': '{current} / {total}',
+35 -36
View File
@@ -54,41 +54,40 @@ const system_notice: TranslationStrings = {
'system_notice.v3014_whitespace_collision.title': 'Acción requerida: conflicto de cuenta de usuario', 'system_notice.v3014_whitespace_collision.title': 'Acción requerida: conflicto de cuenta de usuario',
'system_notice.v3014_whitespace_collision.body': 'system_notice.v3014_whitespace_collision.body':
'La actualización 3.0.14 detectó uno o más conflictos de nombre de usuario o correo electrónico causados por espacios en blanco al inicio o al final de los valores almacenados. Las cuentas afectadas se renombraron automáticamente. Revisa los registros del servidor en busca de líneas que empiecen por **[migration] WHITESPACE COLLISION** para identificar qué cuentas necesitan revisión.', 'La actualización 3.0.14 detectó uno o más conflictos de nombre de usuario o correo electrónico causados por espacios en blanco al inicio o al final de los valores almacenados. Las cuentas afectadas se renombraron automáticamente. Revisa los registros del servidor en busca de líneas que empiecen por **[migration] WHITESPACE COLLISION** para identificar qué cuentas necesitan revisión.',
// 4.0.0 release modal — the release on the left, the note from the maintainer on the right // The release modal. One stable set of keys: each big release swaps the copy in place.
'system_notice.release_400.eyebrow': 'Actualización instalada', 'system_notice.release_notes.eyebrow': 'Actualización instalada',
'system_notice.release_400.tag': 'Versión', 'system_notice.release_notes.headline': 'Tres cosas que TREK ya hace por sí solo.',
'system_notice.release_400.headline': 'La mayor versión que TREK ha tenido jamás.', 'system_notice.release_notes.intro':
'system_notice.release_400.intro': 'Su propia API de lugares, viajes por carretera planificados de principio a fin y tu historial de ubicaciones de nuevo en tus manos.',
'TREK recibe un móvil y un libro. La escribieron diecinueve personas — y con ella se fueron unos ciento cincuenta bugs.', 'system_notice.release_notes.features_label': 'Los protagonistas',
'system_notice.release_400.feature_mobile_title': 'TREK en el móvil', 'system_notice.release_notes.features_aside': 'Y eso no es todo',
'system_notice.release_400.feature_mobile_body': 'system_notice.release_notes.feature_places_title': 'TREK Places API',
'Todo por debajo de 768px es ya una interfaz propia — un dock de cristal, sus propios paneles, su propio planificador. Abre TREK en tu móvil.', 'system_notice.release_notes.feature_places_body':
'system_notice.release_400.feature_studio_title': 'TREK Studio', 'El primer planificador de viajes open source que aloja su propia API de lugares. 73,6 millones de lugares, reconstruidos cada mes. Sin clave, sin cuota.',
'system_notice.release_400.feature_studio_badge': 'Beta', 'system_notice.release_notes.feature_roadtrip_title': 'Addon Roadtrip',
'system_notice.release_400.feature_studio_body': 'system_notice.release_notes.feature_roadtrip_body':
'El PDF de Journey se convirtió en un diseñador de fotolibros. Maqueta el libro cuando se lo pides y luego se aparta.', 'El modo viaje por carretera también planifica el trayecto en coche: la ruta, la distancia, las horas al volante y las paradas. Es un addon, desactivado hasta que un admin lo active.',
'system_notice.release_400.feature_vacay_title': 'Vacay aprende el resto', 'system_notice.release_notes.feature_dawarich_title': 'Integración con Dawarich',
'system_notice.release_400.feature_vacay_body': 'system_notice.release_notes.feature_dawarich_body':
'Medios días, días de compensación y flexibles, vacaciones escolares en la rejilla — y un año que no tiene que empezar en enero.', 'La alternativa autoalojada a Google Timeline, ahora legible desde TREK. TREK lee, y solo lee. Nunca se escribe nada en Dawarich.',
'system_notice.release_400.feature_places_title': 'Lugares que se muestran, archivos que salen', 'system_notice.release_notes.footnote': 'Y una larga lista de cambios más pequeños en el resto de TREK.',
'system_notice.release_400.feature_places_body': 'system_notice.release_notes.notes_label': 'Notas de versión',
'Las fotos y la descripción se rellenan solas antes de guardar un lugar. Y tus archivos ya no tienen que vivir en el disco donde corre TREK.', 'system_notice.release_notes.note_eyebrow': 'Una nota del desarrollador',
'system_notice.release_400.footnote': 'system_notice.release_notes.note_title': 'Sois la razón por la que sigo construyendo TREK.',
'Y estas son cuatro. La 4.0.0 trae varios cientos de cambios más, desde Collections y Atlas hasta todo el servidor por debajo.', 'system_notice.release_notes.note_body':
'system_notice.release_400.note_eyebrow': 'Una nota del desarrollador', 'TREK nació como una pequeña herramienta para mis propios viajes, escrita después del trabajo porque quería una forma mejor de planificarlos. En realidad, nunca ha dejado de crecer. Casi todo lo he construido a altas horas de la noche, los fines de semana, en trenes, junto a un trabajo a jornada completa, y más de una vez me pregunté en silencio si alguien, en algún lugar, llegaría a abrirlo.',
'system_notice.release_400.note_title': 'Gracias por usar TREK.', 'system_notice.release_notes.promise_label': 'La promesa',
'system_notice.release_400.note_body': 'system_notice.release_notes.promise_lead': 'TREK seguirá siendo gratis, para siempre.',
'TREK empezó como una pequeña herramienta para mis propios viajes, escrita en mi tiempo libre. Y lo sigue siendo: tardes, fines de semana, las horas junto a un trabajo a jornada completa.\n\nDurante un tiempo fui solo yo. Ya no — diecinueve personas sacaron esta versión, y miles de personas llegaron con estrellas, issues, traducciones y pull requests. Estoy agradecido por cada parte.', 'system_notice.release_notes.promise_text':
'system_notice.release_400.promise_label': 'La promesa', 'Cada función, cada actualización, para todo el mundo. Sin planes de pago, sin suscripciones, sin trampa.',
'system_notice.release_400.promise_text': 'system_notice.release_notes.note_body_after':
'La parte open source de TREK sigue siendo gratis, para siempre. Sin planes de pago, sin suscripciones, sin trampa. Prometido.', 'Y entonces lo abristeis. En pocos meses erais miles: estrellas, informes de errores, traducciones a idiomas que no hablo, pull requests de gente a la que nunca he conocido. Lo primero que hago cada mañana sigue siendo mirar el repositorio, y todavía me cuesta creérmelo.',
'system_notice.release_400.note_body_after': 'system_notice.release_notes.note_closing': 'Gracias por estar aquí. Un abrazo, Maurice.',
'La 4.0.0 costó semanas de noches en vela — una app de móvil, un diseñador de libros, una migración del servidor, casi todo escrito entre medianoche y las dos. No es una queja: me encanta hacer esto. Es solo la respuesta honesta a cómo sale una versión así de un proyecto de tiempo libre.', 'system_notice.release_notes.support_lead':
'system_notice.release_400.note_closing': 'Gracias por estar aquí.', 'TREK es gratis y siempre lo será, pero los servidores, los dominios y tantas noches en vela no lo son.',
'system_notice.release_400.note_signature': '— Maurice', 'system_notice.release_notes.support_text':
'system_notice.release_400.support_text': 'Si se ha ganado un sitio en tus viajes, invítame a un café y ayuda a que llegue la próxima versión.',
'El apoyo es lo que mantiene esto en marcha — servidores, dominios y las noches en vela que acaban en versiones como esta. Si TREK vale algo para ti, un café es la forma más directa de que siga.', 'system_notice.release_notes.cta_bmc': 'Buy me a coffee',
'system_notice.release_400.cta_bmc': 'Buy me a coffee', 'system_notice.release_notes.cta_kofi': 'Apóyame en Ko-fi',
'system_notice.release_400.cta_kofi': 'Apóyame en Ko-fi',
}; };
export default system_notice; export default system_notice;
+34 -35
View File
@@ -54,40 +54,39 @@ const system_notice: TranslationStrings = {
'system_notice.v3014_whitespace_collision.title': 'Action requise : conflit de compte utilisateur', 'system_notice.v3014_whitespace_collision.title': 'Action requise : conflit de compte utilisateur',
'system_notice.v3014_whitespace_collision.body': 'system_notice.v3014_whitespace_collision.body':
"La mise à niveau 3.0.14 a détecté un ou plusieurs conflits de nom d'utilisateur ou d'adresse e-mail causés par des espaces en début ou en fin de valeur dans les comptes enregistrés. Les comptes concernés ont été renommés automatiquement. Consultez les journaux du serveur pour les lignes commençant par **[migration] WHITESPACE COLLISION** afin d'identifier les comptes nécessitant une vérification.", "La mise à niveau 3.0.14 a détecté un ou plusieurs conflits de nom d'utilisateur ou d'adresse e-mail causés par des espaces en début ou en fin de valeur dans les comptes enregistrés. Les comptes concernés ont été renommés automatiquement. Consultez les journaux du serveur pour les lignes commençant par **[migration] WHITESPACE COLLISION** afin d'identifier les comptes nécessitant une vérification.",
'system_notice.release_400.eyebrow': 'Mise à jour installée', 'system_notice.release_notes.eyebrow': 'Mise à jour installée',
'system_notice.release_400.tag': 'Version', 'system_notice.release_notes.headline': 'Trois choses que TREK fait désormais tout seul.',
'system_notice.release_400.headline': 'La plus grande version de TREK à ce jour.', 'system_notice.release_notes.intro':
'system_notice.release_400.intro': 'Sa propre API de lieux, des road trips planifiés de bout en bout et ton historique de positions de retour entre tes mains.',
'TREK gagne un téléphone, et un livre. Dix-neuf personnes ont écrit cette version — et environ cent cinquante bugs signalés ont disparu au passage.', 'system_notice.release_notes.features_label': "Les têtes d'affiche",
'system_notice.release_400.feature_mobile_title': 'TREK passe au mobile', 'system_notice.release_notes.features_aside': "Et ce n'est pas tout",
'system_notice.release_400.feature_mobile_body': 'system_notice.release_notes.feature_places_title': 'API TREK Places',
'Tout ce qui est sous 768px a désormais sa propre interface — un dock en verre, ses feuilles, son planificateur. Ouvre TREK sur ton téléphone.', 'system_notice.release_notes.feature_places_body':
'system_notice.release_400.feature_studio_title': 'TREK Studio', 'Le premier planificateur de voyage open source qui héberge sa propre API de lieux. 73,6 millions de lieux, reconstruits chaque mois. Sans clé, sans quota.',
'system_notice.release_400.feature_studio_badge': 'Beta', 'system_notice.release_notes.feature_roadtrip_title': 'Addon Roadtrip',
'system_notice.release_400.feature_studio_body': 'system_notice.release_notes.feature_roadtrip_body':
"Le PDF de Journey est devenu un concepteur de livre photo. Il met le livre en page quand tu le demandes, puis s'efface.", "Le mode road trip planifie aussi le trajet en voiture : l'itinéraire, la distance, les heures de route et les arrêts. C'est un addon, désactivé tant qu'un admin ne l'active pas.",
'system_notice.release_400.feature_vacay_title': 'Vacay apprend le reste', 'system_notice.release_notes.feature_dawarich_title': 'Intégration Dawarich',
'system_notice.release_400.feature_vacay_body': 'system_notice.release_notes.feature_dawarich_body':
'Demi-journées, récup et RTT, vacances scolaires dans la grille — et une année de congés qui ne commence pas forcément en janvier.', "L'alternative auto-hébergée à Google Timeline, désormais lisible depuis TREK. TREK lit, et ne fait que lire. Rien n'est jamais réécrit dans Dawarich.",
'system_notice.release_400.feature_places_title': 'Les lieux se présentent, les fichiers déménagent', 'system_notice.release_notes.footnote': 'Et une longue liste de changements plus discrets dans le reste de TREK.',
'system_notice.release_400.feature_places_body': 'system_notice.release_notes.notes_label': 'Notes de version',
'Photos et description se remplissent toutes seules avant que tu enregistres un lieu. Et tes fichiers ne sont plus obligés de vivre sur le disque où tourne TREK.', 'system_notice.release_notes.note_eyebrow': 'Un mot du mainteneur',
'system_notice.release_400.footnote': 'system_notice.release_notes.note_title': "C'est pour vous que je continue à construire TREK.",
"Et ce ne sont que quatre d'entre eux. 4.0.0 apporte plusieurs centaines d'autres changements, de Collections et Atlas jusqu'au serveur en dessous.", 'system_notice.release_notes.note_body':
'system_notice.release_400.note_eyebrow': 'Un mot du mainteneur', "TREK est né comme un petit outil pour mes propres voyages, écrit après le travail parce que je voulais une meilleure façon de les préparer. Il n'a jamais vraiment cessé de grandir. Presque tout ce qui existe aujourd'hui a été construit tard le soir, le week-end, dans le train, à côté d'un travail à temps plein, et bien des soirs je me suis demandé en silence si quelqu'un, quelque part, l'ouvrirait un jour.",
'system_notice.release_400.note_title': "Merci d'utiliser TREK.", 'system_notice.release_notes.promise_label': 'La promesse',
'system_notice.release_400.note_body': 'system_notice.release_notes.promise_lead': 'TREK reste gratuit, pour toujours.',
"TREK a commencé comme un petit outil pour mes propres voyages, écrit sur mon temps libre. Ça l'est toujours : le soir, le week-end, les heures à côté d'un travail à temps plein.\n\nPendant un temps, il n'y avait que moi. Plus maintenant — dix-neuf personnes ont livré cette version, et vous êtes des milliers à être arrivés avec des étoiles, des issues, des traductions et des pull requests. Je suis reconnaissant pour tout ça.", 'system_notice.release_notes.promise_text':
'system_notice.release_400.promise_label': 'La promesse', "Chaque fonctionnalité, chaque mise à jour, pour tout le monde. Pas de formules payantes, pas d'abonnements, aucun piège.",
'system_notice.release_400.promise_text': 'system_notice.release_notes.note_body_after':
"Le côté open source de TREK reste gratuit, pour toujours. Pas de formules payantes, pas d'abonnements, aucun piège. Promis.", "Et puis vous l'avez ouvert. En quelques mois, vous étiez des milliers : des étoiles, des rapports de bugs, des traductions dans des langues que je ne parle pas, des pull requests de personnes que je n'ai jamais rencontrées. Chaque matin, la première chose que je fais est encore d'aller voir le dépôt, et j'ai toujours du mal à y croire.",
'system_notice.release_400.note_body_after': 'system_notice.release_notes.note_closing': "Merci d'être là. Amicalement, Maurice.",
"4.0.0 a demandé des semaines de nuits blanches — une app mobile, un concepteur de livre, une migration serveur, l'essentiel écrit entre minuit et deux heures. Ce n'est pas une plainte : j'adore construire ça. C'est juste la réponse honnête à comment une version de cette taille sort d'un projet de temps libre.", 'system_notice.release_notes.support_lead':
'system_notice.release_400.note_closing': "Merci d'être là.", 'TREK est gratuit et le restera toujours, mais les serveurs, les noms de domaine et toutes ces nuits blanches, eux, ne le sont pas.',
'system_notice.release_400.note_signature': '— Maurice', 'system_notice.release_notes.support_text':
'system_notice.release_400.support_text': "Si TREK s'est fait une place dans tes voyages, offre-moi un café et aide la prochaine version à voir le jour.",
'Le soutien est ce qui fait tourner tout ça — serveurs, domaines, et les nuits blanches qui deviennent des versions comme celle-ci. Si TREK vaut quelque chose pour toi, un café est le moyen le plus direct de continuer.', 'system_notice.release_notes.cta_bmc': 'Buy me a coffee',
'system_notice.release_400.cta_bmc': 'Buy me a coffee', 'system_notice.release_notes.cta_kofi': 'Soutenir sur Ko-fi',
'system_notice.release_400.cta_kofi': 'Soutenir sur Ko-fi',
}; };
export default system_notice; export default system_notice;
+34 -35
View File
@@ -56,40 +56,39 @@ const system_notice: TranslationStrings = {
'system_notice.pager.counter': '{current} / {total}', 'system_notice.pager.counter': '{current} / {total}',
'system_notice.pager.goto': 'Μετάβαση στην ειδοποίηση {n}', 'system_notice.pager.goto': 'Μετάβαση στην ειδοποίηση {n}',
'system_notice.pager.position': 'Ειδοποίηση {current} από {total}', 'system_notice.pager.position': 'Ειδοποίηση {current} από {total}',
'system_notice.release_400.eyebrow': 'Ενημερώθηκε', 'system_notice.release_notes.eyebrow': 'Ενημερώθηκε',
'system_notice.release_400.tag': 'Έκδοση', 'system_notice.release_notes.headline': 'Τρία πράγματα που το TREK κάνει πλέον μόνο του.',
'system_notice.release_400.headline': 'Η μεγαλύτερη έκδοση που είχε ποτέ το TREK.', 'system_notice.release_notes.intro':
'system_notice.release_400.intro': 'Δικό του API τοποθεσιών, οδικά ταξίδια σχεδιασμένα από την αρχή ως το τέλος και το ιστορικό των μετακινήσεών σας ξανά στα χέρια σας.',
'Το TREK αποκτά τηλέφωνο, και βιβλίο. Αυτή την έκδοση την έγραψαν δεκαεννέα άτομα — και μαζί της έφυγαν περίπου εκατόν πενήντα σφάλματα που αναφέρατε.', 'system_notice.release_notes.features_label': 'Τα σημαντικότερα',
'system_notice.release_400.feature_mobile_title': 'Το TREK σε κινητό', 'system_notice.release_notes.features_aside': 'Και δεν είναι μόνο αυτά',
'system_notice.release_400.feature_mobile_body': 'system_notice.release_notes.feature_places_title': 'TREK Places API',
'Οτιδήποτε κάτω από 768px έχει πλέον δικό του περιβάλλον — ένα γυάλινο dock, δικά του πάνελ, δικό του σχεδιαστή ταξιδιού. Ανοίξτε το TREK στο κινητό σας.', 'system_notice.release_notes.feature_places_body':
'system_notice.release_400.feature_studio_title': 'TREK Studio', 'Ο πρώτος σχεδιαστής ταξιδιών ανοιχτού κώδικα που φιλοξενεί το δικό του API τοποθεσιών. 73,6 εκατομμύρια τοποθεσίες, που ξαναχτίζονται κάθε μήνα. Χωρίς κλειδί, χωρίς όρια χρήσης.',
'system_notice.release_400.feature_studio_badge': 'Beta', 'system_notice.release_notes.feature_roadtrip_title': 'Πρόσθετο «Οδικό ταξίδι»',
'system_notice.release_400.feature_studio_body': 'system_notice.release_notes.feature_roadtrip_body':
'Το PDF του Journey έγινε σχεδιαστής βιβλίου φωτογραφιών. Στήνει το βιβλίο όταν του το ζητήσετε, και μετά κάνει στην άκρη.', 'Η λειτουργία οδικού ταξιδιού σχεδιάζει την ίδια την οδήγηση: τη διαδρομή, την απόσταση, τις ώρες και τις στάσεις της. Είναι πρόσθετο και μένει ανενεργό μέχρι να το ενεργοποιήσει ένας διαχειριστής.',
'system_notice.release_400.feature_vacay_title': 'Το Vacay μαθαίνει τα υπόλοιπα', 'system_notice.release_notes.feature_dawarich_title': 'Ενσωμάτωση Dawarich',
'system_notice.release_400.feature_vacay_body': 'system_notice.release_notes.feature_dawarich_body':
'Μισές ημέρες, ρεπό και ευέλικτες ημέρες, σχολικές αργίες στο πλέγμα — και ένα έτος αδειών που δεν χρειάζεται να ξεκινά τον Ιανουάριο.', 'Η εναλλακτική του Google Timeline που φιλοξενείτε μόνοι σας, τώρα ορατή μέσα από το TREK. Το TREK διαβάζει, και μόνο διαβάζει. Τίποτα δεν γράφεται ποτέ πίσω.',
'system_notice.release_400.feature_places_title': 'Οι τοποθεσίες συστήνονται, τα αρχεία φεύγουν', 'system_notice.release_notes.footnote': 'Και ακόμη μια μεγάλη λίστα με μικρότερες αλλαγές σε όλο το υπόλοιπο TREK.',
'system_notice.release_400.feature_places_body': 'system_notice.release_notes.notes_label': 'Σημειώσεις έκδοσης',
'Εικόνες και περιγραφή συμπληρώνονται μόνες τους πριν αποθηκεύσετε μια τοποθεσία. Και τα αρχεία σας δεν χρειάζεται πια να μένουν στον δίσκο όπου τρέχει το TREK.', 'system_notice.release_notes.note_eyebrow': 'Μια σημείωση από τον δημιουργό',
'system_notice.release_400.footnote': 'system_notice.release_notes.note_title': 'Εσείς είστε ο λόγος που συνεχίζω να φτιάχνω το TREK.',
'Και αυτές είναι τέσσερις. Η 4.0.0 φέρνει αρκετές εκατοντάδες ακόμη αλλαγές, από τα Collections και το Atlas μέχρι όλο τον server από κάτω.', 'system_notice.release_notes.note_body':
'system_notice.release_400.note_eyebrow': 'Μια σημείωση από τον δημιουργό', 'Το TREK ξεκίνησε ως ένα μικρό εργαλείο για τα δικά μου ταξίδια, γραμμένο μετά τη δουλειά επειδή ήθελα έναν καλύτερο τρόπο να τα οργανώνω. Από τότε δεν σταμάτησε ποτέ πραγματικά να μεγαλώνει. Σχεδόν ό,τι χρησιμοποιείτε φτιάχτηκε αργά τη νύχτα, τα σαββατοκύριακα, στα τρένα, δίπλα σε μια δουλειά πλήρους απασχόλησης, και ήταν πολλά τα βράδια που αναρωτιόμουν σιωπηλά αν θα το άνοιγε ποτέ κανείς εκεί έξω.',
'system_notice.release_400.note_title': 'Ευχαριστώ που χρησιμοποιείτε το TREK.', 'system_notice.release_notes.promise_label': 'Η υπόσχεση',
'system_notice.release_400.note_body': 'system_notice.release_notes.promise_lead': 'Το TREK μένει δωρεάν, για πάντα.',
'Το TREK ξεκίνησε ως ένα μικρό εργαλείο για τα δικά μου ταξίδια, γραμμένο στον ελεύθερό μου χρόνο. Έτσι είναι ακόμα: βράδια, σαββατοκύριακα, οι ώρες δίπλα σε μια δουλειά πλήρους απασχόλησης.\n\nΓια κάποιο διάστημα ήμουν μόνο εγώ. Όχι πια — δεκαεννέα άτομα έβγαλαν αυτή την έκδοση, και χιλιάδες από εσάς ήρθατε με αστέρια, αναφορές, μεταφράσεις και pull requests. Είμαι ευγνώμων για κάθε κομμάτι της.', 'system_notice.release_notes.promise_text':
'system_notice.release_400.promise_label': 'Η υπόσχεση', 'Κάθε λειτουργία, κάθε ενημέρωση, για όλους. Καμία έκδοση επί πληρωμή, καμία συνδρομή, καμία παγίδα.',
'system_notice.release_400.promise_text': 'system_notice.release_notes.note_body_after':
'Η ανοιχτού κώδικα πλευρά του TREK μένει δωρεάν, για πάντα. Καμία έκδοση επί πληρωμή, καμία συνδρομή, καμία παγίδα. Το υπόσχομαι.', 'Και τότε το ανοίξατε. Μέσα σε λίγους μήνες γίνατε χιλιάδες: αστέρια, αναφορές σφαλμάτων, μεταφράσεις σε γλώσσες που δεν μιλάω, pull requests από ανθρώπους που δεν έχω γνωρίσει ποτέ. Ακόμα ανοίγω το αποθετήριο πρώτο πράγμα κάθε πρωί, και ακόμα δεν μου φαίνεται εντελώς αληθινό.',
'system_notice.release_400.note_body_after': 'system_notice.release_notes.note_closing': 'Σας ευχαριστώ που είστε εδώ. Φιλικά, Maurice.',
'Η 4.0.0 πήρε εβδομάδες από ξενύχτια — μια εφαρμογή για κινητό, έναν σχεδιαστή βιβλίου, μια μετάβαση του server, τα περισσότερα γραμμένα ανάμεσα στα μεσάνυχτα και τις δύο. Δεν είναι παράπονο: μου αρέσει να το φτιάχνω. Είναι απλώς η ειλικρινής απάντηση στο πώς βγαίνει μια τόσο μεγάλη έκδοση από ένα έργο του ελεύθερου χρόνου.', 'system_notice.release_notes.support_lead':
'system_notice.release_400.note_closing': 'Σας ευχαριστώ που είστε εδώ.', 'Το TREK είναι δωρεάν και θα είναι πάντα, όμως οι servers, τα domains και τα πολλά ξενύχτια δεν είναι.',
'system_notice.release_400.note_signature': '— Maurice', 'system_notice.release_notes.support_text':
'system_notice.release_400.support_text': 'Αν έχει κερδίσει μια θέση στα ταξίδια σας, κεράστε με έναν καφέ και βοηθήστε να έρθει η επόμενη έκδοση.',
'Η στήριξη είναι αυτό που κρατά όλο αυτό ζωντανό — servers, domains και οι ξενύχτιες που γίνονται εκδόσεις σαν κι αυτή. Αν το TREK αξίζει κάτι για εσάς, ένας καφές είναι ο πιο άμεσος τρόπος να συνεχίσει.', 'system_notice.release_notes.cta_bmc': 'Buy me a coffee',
'system_notice.release_400.cta_bmc': 'Buy me a coffee', 'system_notice.release_notes.cta_kofi': 'Στηρίξτε στο Ko-fi',
'system_notice.release_400.cta_kofi': 'Στηρίξτε στο Ko-fi',
}; };
export default system_notice; export default system_notice;
+34 -35
View File
@@ -54,40 +54,39 @@ const system_notice: TranslationStrings = {
'system_notice.v3014_whitespace_collision.title': 'Szükséges beavatkozás: felhasználói fiókütközés', 'system_notice.v3014_whitespace_collision.title': 'Szükséges beavatkozás: felhasználói fiókütközés',
'system_notice.v3014_whitespace_collision.body': 'system_notice.v3014_whitespace_collision.body':
'A 3.0.14-es frissítés egy vagy több felhasználónév- vagy e-mail-ütközést észlelt, amelyeket a tárolt értékek elején vagy végén lévő szóközök okoztak. Az érintett fiókok automatikusan át lettek nevezve. Ellenőrizze a szervernaplókat a **[migration] WHITESPACE COLLISION** kezdetű soroknál a felülvizsgálatot igénylő fiókok azonosításához.', 'A 3.0.14-es frissítés egy vagy több felhasználónév- vagy e-mail-ütközést észlelt, amelyeket a tárolt értékek elején vagy végén lévő szóközök okoztak. Az érintett fiókok automatikusan át lettek nevezve. Ellenőrizze a szervernaplókat a **[migration] WHITESPACE COLLISION** kezdetű soroknál a felülvizsgálatot igénylő fiókok azonosításához.',
'system_notice.release_400.eyebrow': 'Frissítés telepítve', 'system_notice.release_notes.eyebrow': 'Frissítés telepítve',
'system_notice.release_400.tag': 'Kiadás', 'system_notice.release_notes.headline': 'Három dolog, amit a TREK mostantól magától csinál.',
'system_notice.release_400.headline': 'A TREK eddigi legnagyobb kiadása.', 'system_notice.release_notes.intro':
'system_notice.release_400.intro': 'Saját hely-API, elejétől a végéig megtervezett autós utak és a helyelőzményeid újra a saját kezedben.',
'A TREK kap egy telefont és egy könyvet. Ezt tizenkilencen írták — és nagyjából százötven bejelentett hiba ment vele.', 'system_notice.release_notes.features_label': 'A fő újdonságok',
'system_notice.release_400.feature_mobile_title': 'A TREK mobilon', 'system_notice.release_notes.features_aside': 'És ez még nem minden',
'system_notice.release_400.feature_mobile_body': 'system_notice.release_notes.feature_places_title': 'TREK Places API',
'Minden 768px alatt már saját felület — üveg dokk, saját panelek, saját utazástervező. Nyisd meg a TREK-et a telefonodon.', 'system_notice.release_notes.feature_places_body':
'system_notice.release_400.feature_studio_title': 'TREK Studio', 'Az első nyílt forráskódú utazástervező, amely saját hely-API-t üzemeltet. 73,6 millió hely, havonta újraépítve. Nincs kulcs, nincs kvóta.',
'system_notice.release_400.feature_studio_badge': 'Beta', 'system_notice.release_notes.feature_roadtrip_title': 'Autós út bővítmény',
'system_notice.release_400.feature_studio_body': 'system_notice.release_notes.feature_roadtrip_body':
'A Journey PDF fotókönyv-tervezővé vált. Megszerkeszti a könyvet, ha kéred, aztán félreáll.', 'Az Autós út mód magát a vezetést is megtervezi: az útvonalat, a távolságot, a vezetési időt és a megállókat. Ez egy bővítmény, amely addig ki van kapcsolva, amíg egy rendszergazda be nem kapcsolja.',
'system_notice.release_400.feature_vacay_title': 'A Vacay megtanulja a többit', 'system_notice.release_notes.feature_dawarich_title': 'Dawarich-integráció',
'system_notice.release_400.feature_vacay_body': 'system_notice.release_notes.feature_dawarich_body':
'Fél napok, csúsztatott és rugalmas napok, iskolai szünetek a naptárban — és szabadságév, aminek nem kell januárban kezdődnie.', 'A Google Timeline self-hosted megfelelője, mostantól a TREK-ben is olvasható. A TREK olvas, és csak olvas. Soha semmit nem ír vissza.',
'system_notice.release_400.feature_places_title': 'Helyek megmutatkoznak, fájlok költöznek', 'system_notice.release_notes.footnote': 'Plusz rengeteg kisebb változás a TREK többi részében.',
'system_notice.release_400.feature_places_body': 'system_notice.release_notes.notes_label': 'Kiadási jegyzetek',
'Képek és leírás maguktól kitöltődnek, mielőtt mentenél egy helyet. A feltöltéseidnek pedig már nem kell azon a lemezen lakniuk, amin a TREK fut.', 'system_notice.release_notes.note_eyebrow': 'Egy szó a fejlesztőtől',
'system_notice.release_400.footnote': 'system_notice.release_notes.note_title': 'Miattad építem tovább a TREK-et.',
'És ez négy közülük. A 4.0.0 több száz további változást hoz, a Collections-től és az Atlastól az egész alatta futó szerverig.', 'system_notice.release_notes.note_body':
'system_notice.release_400.note_eyebrow': 'Egy szó a fejlesztőtől', 'A TREK egy kis eszközként indult a saját utazásaimhoz, munka után írtam, mert jobban szerettem volna megtervezni őket. Azóta igazából folyamatosan nő. Szinte mindent, amit használsz, késő éjjel, hétvégén, vonaton, egy teljes állás mellett építettem, és sok olyan este volt, amikor csendben azon tűnődtem, megnyitja-e egyáltalán valaki valaha.',
'system_notice.release_400.note_title': 'Köszönöm, hogy a TREK-et használod.', 'system_notice.release_notes.promise_label': 'Az ígéret',
'system_notice.release_400.note_body': 'system_notice.release_notes.promise_lead': 'A TREK ingyenes marad, örökre.',
'A TREK egy kis eszközként indult a saját utazásaimhoz, a szabadidőmben írva. Ma is az: esték, hétvégék, a teljes állás melletti órák.\n\nEgy ideig csak én voltam. Már nem — ezt a kiadást tizenkilencen szállították, és több ezren érkeztetek csillagokkal, issue-kkal, fordításokkal és pull requestekkel. Mindegyikért hálás vagyok.', 'system_notice.release_notes.promise_text':
'system_notice.release_400.promise_label': 'Az ígéret', 'Minden funkció, minden frissítés, mindenkinek. Nincsenek fizetős csomagok, nincsenek előfizetések, nincs átverés.',
'system_notice.release_400.promise_text': 'system_notice.release_notes.note_body_after':
'A TREK nyílt forráskódú oldala ingyenes marad, örökre. Nincsenek fizetős csomagok, nincsenek előfizetések, nincs átverés. Ígérem.', 'Aztán megnyitottátok. Néhány hónap alatt több ezren lettetek: csillagok, hibajelentések, fordítások olyan nyelvekre, amelyeket nem beszélek, pull requestek olyanoktól, akikkel sosem találkoztam. Még mindig a repóval kezdem minden reggelt, és még mindig nem egészen tűnik valóságosnak.',
'system_notice.release_400.note_body_after': 'system_notice.release_notes.note_closing': 'Köszönöm, hogy itt vagy. Maurice',
'A 4.0.0 heteknyi késő éjszakába került — egy telefonos felület, egy könyvtervező, egy szerverköltözés, java része éjfél és kettő között írva. Nem panasz: szeretem építeni. Csak az őszinte válasz arra, hogyan születik ekkora kiadás egy szabadidős projektből.', 'system_notice.release_notes.support_lead':
'system_notice.release_400.note_closing': 'Köszönöm, hogy itt vagy.', 'A TREK ingyenes, és mindig az is marad, de a szerverek, a domainek és a sok késő éjszaka nem azok.',
'system_notice.release_400.note_signature': '— Maurice', 'system_notice.release_notes.support_text':
'system_notice.release_400.support_text': 'Ha kiérdemelt egy helyet az utazásaid között, hívj meg egy kávéra, és segíts, hogy jöhessen a következő kiadás.',
'A támogatás tartja életben — szerverek, domainek, és a késő éjszakák, amikből ilyen kiadások lesznek. Ha a TREK ér neked valamit, egy kávé a legközvetlenebb módja, hogy tovább menjen.', 'system_notice.release_notes.cta_bmc': 'Buy me a coffee',
'system_notice.release_400.cta_bmc': 'Buy me a coffee', 'system_notice.release_notes.cta_kofi': 'Támogass a Ko-fi-n',
'system_notice.release_400.cta_kofi': 'Támogass a Ko-fi-n',
}; };
export default system_notice; export default system_notice;
+34 -35
View File
@@ -54,40 +54,39 @@ const system_notice: TranslationStrings = {
'system_notice.v3014_whitespace_collision.title': 'Tindakan diperlukan: konflik akun pengguna', 'system_notice.v3014_whitespace_collision.title': 'Tindakan diperlukan: konflik akun pengguna',
'system_notice.v3014_whitespace_collision.body': 'system_notice.v3014_whitespace_collision.body':
'Pembaruan 3.0.14 mendeteksi satu atau lebih konflik nama pengguna atau email yang disebabkan oleh spasi di awal atau akhir nilai yang tersimpan. Akun yang terpengaruh telah diganti nama secara otomatis. Periksa log server untuk baris yang dimulai dengan **[migration] WHITESPACE COLLISION** guna mengidentifikasi akun mana yang perlu ditinjau.', 'Pembaruan 3.0.14 mendeteksi satu atau lebih konflik nama pengguna atau email yang disebabkan oleh spasi di awal atau akhir nilai yang tersimpan. Akun yang terpengaruh telah diganti nama secara otomatis. Periksa log server untuk baris yang dimulai dengan **[migration] WHITESPACE COLLISION** guna mengidentifikasi akun mana yang perlu ditinjau.',
'system_notice.release_400.eyebrow': 'Pembaruan terpasang', 'system_notice.release_notes.eyebrow': 'Pembaruan terpasang',
'system_notice.release_400.tag': 'Rilis', 'system_notice.release_notes.headline': 'Tiga hal yang kini dikerjakan TREK sendiri.',
'system_notice.release_400.headline': 'Rilis terbesar yang pernah ada di TREK.', 'system_notice.release_notes.intro':
'system_notice.release_400.intro': 'API tempat miliknya sendiri, perjalanan darat yang direncanakan dari awal sampai akhir, dan riwayat lokasi yang kembali ke tangan Anda.',
'TREK kini punya ponsel, dan sebuah buku. Sembilan belas orang menulis rilis ini — dan sekitar seratus lima puluh laporan bug ikut diperbaiki.', 'system_notice.release_notes.features_label': 'Sorotan utama',
'system_notice.release_400.feature_mobile_title': 'TREK kini mobile', 'system_notice.release_notes.features_aside': 'Masih banyak lagi',
'system_notice.release_400.feature_mobile_body': 'system_notice.release_notes.feature_places_title': 'TREK Places API',
'Semua di bawah 768px kini antarmuka tersendiri — dock kaca, sheet sendiri, perencana perjalanan sendiri. Buka TREK di ponsel Anda.', 'system_notice.release_notes.feature_places_body':
'system_notice.release_400.feature_studio_title': 'TREK Studio', 'Perencana perjalanan open source pertama yang menjalankan API tempatnya sendiri. 73,6 juta tempat, dibangun ulang setiap bulan. Tanpa kunci API, tanpa kuota.',
'system_notice.release_400.feature_studio_badge': 'Beta', 'system_notice.release_notes.feature_roadtrip_title': 'Addon Perjalanan Darat',
'system_notice.release_400.feature_studio_body': 'system_notice.release_notes.feature_roadtrip_body':
'PDF Journey berubah jadi perancang buku foto. Ia menata bukunya saat Anda minta, lalu menyingkir.', 'Mode perjalanan darat ikut merencanakan perjalanan berkendaranya: rute, jarak, lama berkendara, dan perhentiannya. Ini sebuah addon, nonaktif sampai admin mengaktifkannya.',
'system_notice.release_400.feature_vacay_title': 'Vacay belajar sisanya', 'system_notice.release_notes.feature_dawarich_title': 'Integrasi Dawarich',
'system_notice.release_400.feature_vacay_body': 'system_notice.release_notes.feature_dawarich_body':
'Setengah hari, hari pengganti dan fleksibel, libur sekolah di kalender — dan tahun cuti yang tak harus mulai Januari.', 'Alternatif self-hosted untuk Google Timeline, kini bisa dibaca langsung di TREK. TREK hanya membaca, tidak lebih. Tidak ada satu pun yang ditulis balik.',
'system_notice.release_400.feature_places_title': 'Tempat tampil sendiri, file pindah keluar', 'system_notice.release_notes.footnote': 'Ditambah deretan panjang perubahan kecil di bagian TREK lainnya.',
'system_notice.release_400.feature_places_body': 'system_notice.release_notes.notes_label': 'Catatan rilis',
'Gambar dan deskripsi terisi sendiri sebelum Anda menyimpan tempat. Dan unggahan Anda tak harus lagi tinggal di disk tempat TREK berjalan.', 'system_notice.release_notes.note_eyebrow': 'Catatan dari maintainer',
'system_notice.release_400.footnote': 'system_notice.release_notes.note_title': 'Kalianlah alasan saya terus membangun TREK.',
'Dan ini baru empat di antaranya. 4.0.0 membawa beberapa ratus perubahan lain, dari Collections dan Atlas sampai seluruh server di baliknya.', 'system_notice.release_notes.note_body':
'system_notice.release_400.note_eyebrow': 'Catatan dari maintainer', 'TREK dimulai sebagai alat kecil untuk perjalanan saya sendiri, saya tulis sepulang kerja karena ingin cara yang lebih baik untuk merencanakannya. Sejak itu ia tidak pernah benar-benar berhenti tumbuh. Hampir semua yang kalian pakai dibangun larut malam, di akhir pekan, di kereta, di samping pekerjaan penuh waktu, dan tak sedikit malam saya diam-diam bertanya-tanya apakah akan ada orang di luar sana yang membukanya.',
'system_notice.release_400.note_title': 'Terima kasih telah memakai TREK.', 'system_notice.release_notes.promise_label': 'Janjinya',
'system_notice.release_400.note_body': 'system_notice.release_notes.promise_lead': 'TREK tetap gratis, selamanya.',
'TREK dimulai sebagai alat kecil untuk perjalanan saya sendiri, ditulis di waktu luang. Sampai sekarang masih begitu: malam hari, akhir pekan, jam-jam di sela pekerjaan penuh waktu.\n\nDulu hanya saya sendiri. Sekarang tidak lagi — sembilan belas orang merilis versi ini, dan ribuan dari kalian datang dengan bintang, issue, terjemahan dan pull request. Saya bersyukur atas setiap bagiannya.', 'system_notice.release_notes.promise_text':
'system_notice.release_400.promise_label': 'Janjinya', 'Setiap fitur, setiap pembaruan, untuk semua orang. Tanpa paket berbayar, tanpa langganan, tanpa syarat tersembunyi.',
'system_notice.release_400.promise_text': 'system_notice.release_notes.note_body_after':
'Sisi open source TREK tetap gratis, selamanya. Tanpa paket berbayar, tanpa langganan, tanpa syarat tersembunyi. Saya janji.', 'Lalu kalian datang. Dalam beberapa bulan saja jumlah kalian sudah ribuan: bintang, laporan bug, terjemahan ke bahasa yang tidak saya kuasai, pull request dari orang-orang yang belum pernah saya temui. Sampai sekarang, hal pertama yang saya lakukan setiap pagi masih membuka repositori, dan rasanya masih belum sepenuhnya nyata.',
'system_notice.release_400.note_body_after': 'system_notice.release_notes.note_closing': 'Terima kasih telah berada di sini. Salam hangat, Maurice.',
'4.0.0 menghabiskan berminggu-minggu malam larut — aplikasi ponsel, perancang buku, migrasi server, sebagian besar ditulis antara pukul dua belas dan dua. Bukan keluhan: saya senang membangun ini. Ini cuma jawaban jujur bagaimana rilis sebesar ini keluar dari proyek waktu luang.', 'system_notice.release_notes.support_lead':
'system_notice.release_400.note_closing': 'Terima kasih telah berada di sini.', 'TREK gratis dan akan selalu begitu, tetapi server, domain, dan begitu banyak malam larut tidaklah gratis.',
'system_notice.release_400.note_signature': '— Maurice', 'system_notice.release_notes.support_text':
'system_notice.release_400.support_text': 'Jika TREK sudah mendapat tempat dalam perjalananmu, traktir saya secangkir kopi dan bantu rilis berikutnya terus hadir.',
'Dukungan itulah yang membuat semua ini berjalan — server, domain, dan malam-malam larut yang berubah jadi rilis seperti ini. Jika TREK berarti bagimu, secangkir kopi adalah cara paling langsung untuk menjaganya tetap jalan.', 'system_notice.release_notes.cta_bmc': 'Buy me a coffee',
'system_notice.release_400.cta_bmc': 'Buy me a coffee', 'system_notice.release_notes.cta_kofi': 'Dukung di Ko-fi',
'system_notice.release_400.cta_kofi': 'Dukung di Ko-fi',
}; };
export default system_notice; export default system_notice;
+34 -35
View File
@@ -54,40 +54,39 @@ const system_notice: TranslationStrings = {
'system_notice.v3014_whitespace_collision.title': 'Azione richiesta: conflitto di account utente', 'system_notice.v3014_whitespace_collision.title': 'Azione richiesta: conflitto di account utente',
'system_notice.v3014_whitespace_collision.body': 'system_notice.v3014_whitespace_collision.body':
"L'aggiornamento 3.0.14 ha rilevato uno o più conflitti di nome utente o e-mail causati da spazi iniziali o finali nei valori memorizzati. Gli account interessati sono stati rinominati automaticamente. Controlla i log del server per le righe che iniziano con **[migration] WHITESPACE COLLISION** per identificare quali account richiedono revisione.", "L'aggiornamento 3.0.14 ha rilevato uno o più conflitti di nome utente o e-mail causati da spazi iniziali o finali nei valori memorizzati. Gli account interessati sono stati rinominati automaticamente. Controlla i log del server per le righe che iniziano con **[migration] WHITESPACE COLLISION** per identificare quali account richiedono revisione.",
'system_notice.release_400.eyebrow': 'Aggiornato', 'system_notice.release_notes.eyebrow': 'Aggiornato',
'system_notice.release_400.tag': 'Versione', 'system_notice.release_notes.headline': 'Tre cose che TREK ora fa da solo.',
'system_notice.release_400.headline': 'La versione più grande di sempre di TREK.', 'system_notice.release_notes.intro':
'system_notice.release_400.intro': "Un'API dei luoghi tutta sua, viaggi su strada pianificati dall'inizio alla fine e la cronologia delle tue posizioni di nuovo nelle tue mani.",
"TREK riceve un telefono, e un libro. Questa l'hanno scritta in diciannove — e con lei se ne sono andati circa centocinquanta bug segnalati.", 'system_notice.release_notes.features_label': 'I protagonisti',
'system_notice.release_400.feature_mobile_title': 'TREK diventa mobile', 'system_notice.release_notes.features_aside': 'E non è tutto',
'system_notice.release_400.feature_mobile_body': 'system_notice.release_notes.feature_places_title': 'TREK Places API',
"Tutto sotto i 768px ora è un'interfaccia a sé — una dock in vetro, i suoi pannelli, il suo pianificatore di viaggi. Apri TREK dal telefono.", 'system_notice.release_notes.feature_places_body':
'system_notice.release_400.feature_studio_title': 'TREK Studio', 'Il primo pianificatore di viaggi open source che ospita una propria API dei luoghi. 73,6 milioni di luoghi, ricostruiti ogni mese. Nessuna chiave, nessun limite.',
'system_notice.release_400.feature_studio_badge': 'Beta', 'system_notice.release_notes.feature_roadtrip_title': 'Addon Viaggio su strada',
'system_notice.release_400.feature_studio_body': 'system_notice.release_notes.feature_roadtrip_body':
'Il PDF di Journey è diventato un editor di libri fotografici. Impagina il libro quando glielo chiedi, poi si toglie di mezzo.', 'La modalità viaggio su strada pianifica il tragitto vero e proprio: il percorso, la distanza, le ore di guida e le soste. È un componente aggiuntivo, disattivato finché un admin non lo attiva.',
'system_notice.release_400.feature_vacay_title': 'Vacay impara il resto', 'system_notice.release_notes.feature_dawarich_title': 'Integrazione Dawarich',
'system_notice.release_400.feature_vacay_body': 'system_notice.release_notes.feature_dawarich_body':
'Mezze giornate, recuperi e giorni flessibili, vacanze scolastiche nel calendario — e un anno di ferie che non deve iniziare a gennaio.', "L'alternativa self-hosted a Google Timeline, ora consultabile dentro TREK. TREK legge, e si limita a leggere. Non scrive mai nulla indietro.",
'system_notice.release_400.feature_places_title': 'I luoghi si mostrano, i file traslocano', 'system_notice.release_notes.footnote': 'E in più una lunga lista di piccole modifiche in tutto il resto di TREK.',
'system_notice.release_400.feature_places_body': 'system_notice.release_notes.notes_label': 'Note di rilascio',
'Immagini e descrizione si compilano da sole prima che tu salvi un luogo. E i tuoi caricamenti non devono più stare sul disco dove gira TREK.', 'system_notice.release_notes.note_eyebrow': 'Una nota dal maintainer',
'system_notice.release_400.footnote': 'system_notice.release_notes.note_title': 'Siete voi il motivo per cui continuo a sviluppare TREK.',
'E queste sono quattro. La 4.0.0 porta diverse centinaia di altre modifiche, da Collections e Atlas fino a tutto il server sotto.', 'system_notice.release_notes.note_body':
'system_notice.release_400.note_eyebrow': 'Una nota dal maintainer', 'TREK è nato come un piccolo strumento per i miei viaggi, scritto dopo il lavoro perché volevo un modo migliore per pianificarli. Non ha mai davvero smesso di crescere. Quasi tutto ciò che usate è stato costruito a tarda notte, nei weekend, in treno, accanto a un lavoro a tempo pieno, e ci sono state tante sere in cui mi chiedevo in silenzio se qualcuno là fuori lo avrebbe mai aperto.',
'system_notice.release_400.note_title': 'Grazie per usare TREK.', 'system_notice.release_notes.promise_label': 'La promessa',
'system_notice.release_400.note_body': 'system_notice.release_notes.promise_lead': 'TREK resta gratuito, per sempre.',
"TREK è nato come un piccolo strumento per i miei viaggi, scritto nel tempo libero. Lo è ancora: sere, weekend, le ore accanto a un lavoro a tempo pieno.\n\nPer un po' sono stato solo io. Non più — questa versione l'hanno portata in diciannove, e migliaia di voi sono arrivati con stelle, issue, traduzioni e pull request. Sono grato per ogni parte di tutto questo.", 'system_notice.release_notes.promise_text':
'system_notice.release_400.promise_label': 'La promessa', 'Ogni funzionalità, ogni aggiornamento, per tutti. Nessun piano a pagamento, nessun abbonamento, nessuna fregatura.',
'system_notice.release_400.promise_text': 'system_notice.release_notes.note_body_after':
'La parte open source di TREK resta gratuita, per sempre. Nessun piano a pagamento, nessun abbonamento, nessuna fregatura. Promesso.', "E poi l'avete aperto. In pochi mesi eravate migliaia: stelle, segnalazioni di bug, traduzioni in lingue che non parlo, pull request da persone che non ho mai incontrato. Ogni mattina la prima cosa che faccio è ancora controllare il repository, e ancora non mi sembra del tutto vero.",
'system_notice.release_400.note_body_after': 'system_notice.release_notes.note_closing': 'Grazie per essere qui. Un saluto da Maurice.',
"La 4.0.0 è costata settimane di notti tarde — un'app per il telefono, un editor di libri, una migrazione del server, quasi tutto scritto tra mezzanotte e le due. Non è una lamentela: mi piace costruirlo. È solo la risposta onesta a come una versione così grande esca da un progetto del tempo libero.", 'system_notice.release_notes.support_lead':
'system_notice.release_400.note_closing': 'Grazie per essere qui.', 'TREK è gratuito e lo sarà sempre, ma server, domini e tante notti insonni non lo sono.',
'system_notice.release_400.note_signature': '— Maurice', 'system_notice.release_notes.support_text':
'system_notice.release_400.support_text': 'Se TREK si è guadagnato un posto nei tuoi viaggi, offrimi un caffè e aiutami a far arrivare la prossima versione.',
'Il sostegno è ciò che tiene in piedi tutto questo — server, domini e le notti tarde che diventano versioni come questa. Se TREK vale qualcosa per te, un caffè è il modo più diretto per farlo continuare.', 'system_notice.release_notes.cta_bmc': 'Buy me a coffee',
'system_notice.release_400.cta_bmc': 'Buy me a coffee', 'system_notice.release_notes.cta_kofi': 'Supporta su Ko-fi',
'system_notice.release_400.cta_kofi': 'Supporta su Ko-fi',
}; };
export default system_notice; export default system_notice;
+34 -35
View File
@@ -52,40 +52,39 @@ const system_notice: TranslationStrings = {
'system_notice.pager.counter': '{current} / {total}', 'system_notice.pager.counter': '{current} / {total}',
'system_notice.pager.goto': '通知{n}へ', 'system_notice.pager.goto': '通知{n}へ',
'system_notice.pager.position': '{total}件中{current}件目', 'system_notice.pager.position': '{total}件中{current}件目',
'system_notice.release_400.eyebrow': 'アップデート完了', 'system_notice.release_notes.eyebrow': 'アップデート完了',
'system_notice.release_400.tag': 'リリース', 'system_notice.release_notes.headline': 'TREKが自前でできるようになった、3つのこと。',
'system_notice.release_400.headline': 'TREK史上、最大のリリースです。', 'system_notice.release_notes.intro':
'system_notice.release_400.intro': '自前の場所API、出発から到着まで計画できるロードトリップ、そしてあなたの手元に戻ってくる位置情報の履歴。',
'TREKにスマホと、本が加わりました。19人で書き上げ、報告されていたバグ約150件も一緒に片づきました。', 'system_notice.release_notes.features_label': '今回の目玉',
'system_notice.release_400.feature_mobile_title': 'TREKがモバイルへ', 'system_notice.release_notes.features_aside': 'ほんの一部です',
'system_notice.release_400.feature_mobile_body': 'system_notice.release_notes.feature_places_title': 'TREK Places API',
'768px未満は専用のインターフェースです。ガラス調のドック、専用のシート、専用の旅行プランナー。スマホでTREKを開いてください。', 'system_notice.release_notes.feature_places_body':
'system_notice.release_400.feature_studio_title': 'TREK Studio', '場所APIを自前で運用する、初めてのオープンソース旅行プランナーです。7,360万件の場所を毎月作り直しています。APIキーも利用上限もありません。',
'system_notice.release_400.feature_studio_badge': 'Beta', 'system_notice.release_notes.feature_roadtrip_title': 'ロードトリップアドオン',
'system_notice.release_400.feature_studio_body': 'system_notice.release_notes.feature_roadtrip_body':
'JourneyのPDFがフォトブックのデザイナーになりました。頼めばレイアウトを組み、あとは邪魔をしません。', 'ロードトリップモードは、ドライブそのものを計画します。ルート、距離、運転時間、立ち寄り先まで。アドオンなので、管理者が有効にするまではオフのままです。',
'system_notice.release_400.feature_vacay_title': 'Vacayが残りを覚える', 'system_notice.release_notes.feature_dawarich_title': 'Dawarich連携',
'system_notice.release_400.feature_vacay_body': 'system_notice.release_notes.feature_dawarich_body':
'半休、代休とフレックス、カレンダーに並ぶ学校の休暇。そして1月始まりでなくてもいい休暇年度。', 'Google Timelineのセルフホスト版とも言えるDawarichを、TREKの中で読めるようになりました。TREKは読み取るだけで、それ以上のことはしません。書き戻すことは一切ありません。',
'system_notice.release_400.feature_places_title': '場所は自ら名乗り、ファイルは外へ', 'system_notice.release_notes.footnote': 'ほかにも、TREKのあちこちに細かな変更がたくさん入っています。',
'system_notice.release_400.feature_places_body': 'system_notice.release_notes.notes_label': 'リリースノート',
'場所を保存する前に、写真と説明がひとりでに埋まります。アップロードしたファイルも、TREKが動くディスクに置かなくてよくなりました。', 'system_notice.release_notes.note_eyebrow': '開発者より',
'system_notice.release_400.footnote': 'system_notice.release_notes.note_title': 'あなたがいるから、TREKを作り続けています。',
'これはそのうちの4つです。4.0.0にはCollectionsやAtlasから土台のサーバーまで、数百の変更が入っています。', 'system_notice.release_notes.note_body':
'system_notice.release_400.note_eyebrow': '開発者より', 'TREKは、自分の旅のための小さなツールとして始まりました。もっといい計画の立て方が欲しくて、仕事のあとに書いたものです。それからずっと、大きくなり続けてきました。いま使っていただいている機能のほとんどは、本業のかたわら、深夜や週末、電車の中で作ったものです。こんなもの、誰かが開いてくれる日は来るのだろうか。そうひとりで考えた夜も、何度もありました。',
'system_notice.release_400.note_title': 'TREKを使ってくれてありがとう。', 'system_notice.release_notes.promise_label': '約束',
'system_notice.release_400.note_body': 'system_notice.release_notes.promise_lead': 'TREKは、ずっと無料です。',
'TREKは自分の旅のために、空いた時間で作った小さなツールとして始まりました。今もそれは変わりません。夜と週末、本業の合間の時間です。\n\nしばらくは私一人でした。もう違います。このリリースは19人で送り出し、何千もの人がスター、Issue、翻訳、プルリクエストを持って集まってくれました。そのすべてに感謝しています。', 'system_notice.release_notes.promise_text':
'system_notice.release_400.promise_label': '約束', 'すべての機能も、すべてのアップデートも、すべての人に。有料プランも、サブスクも、隠れた仕掛けもありません。',
'system_notice.release_400.promise_text': 'system_notice.release_notes.note_body_after':
'TREKのオープンソースはずっと無料です。有料プランも、サブスクも、隠れた仕掛けもありません。約束します。', 'そして、あなたが開いてくれました。数か月のうちに、それが何千人にもなりました。スター、バグ報告、私の話せない言語への翻訳、会ったこともない人からのプルリクエスト。今でも毎朝いちばんにリポジトリを確認していますが、まだ少し夢のように感じています。',
'system_notice.release_400.note_body_after': 'system_notice.release_notes.note_closing': 'ここにいてくれて、ありがとう。Mauriceより',
'4.0.0には何週間もの夜なべがかかりました。スマホの画面、フォトブックのデザイナー、サーバーの移行。多くは深夜0時から2時のあいだに書きました。愚痴ではありません。作るのが好きです。この規模のリリースが片手間のプロジェクトからどう出るか、正直に答えればこうです。', 'system_notice.release_notes.support_lead':
'system_notice.release_400.note_closing': 'ここにいてくれて、ありがとう。', 'TREKは無料で、これからもずっと無料です。でも、サーバーやドメイン、数えきれない夜なべはタダではありません。',
'system_notice.release_400.note_signature': '— Maurice', 'system_notice.release_notes.support_text':
'system_notice.release_400.support_text': 'TREKがあなたの旅に欠かせないものになっていたら、コーヒーを一杯おごってください。次のリリースを届ける力になります。',
'これを続けさせてくれているのは応援です。サーバー代、ドメイン代、そして今回のようなリリースになる夜なべ。TREKに価値を感じてもらえたなら、コーヒー一杯がいちばん直接的な支えになります。', 'system_notice.release_notes.cta_bmc': 'Buy me a coffee',
'system_notice.release_400.cta_bmc': 'Buy me a coffee', 'system_notice.release_notes.cta_kofi': 'Ko-fiで応援する',
'system_notice.release_400.cta_kofi': 'Ko-fiで応援する',
}; };
export default system_notice; export default system_notice;
+34 -35
View File
@@ -54,40 +54,39 @@ const system_notice: TranslationStrings = {
'system_notice.pager.counter': '{current} / {total}', 'system_notice.pager.counter': '{current} / {total}',
'system_notice.pager.goto': '{n}번 공지로 이동', 'system_notice.pager.goto': '{n}번 공지로 이동',
'system_notice.pager.position': '공지 {current}/{total}', 'system_notice.pager.position': '공지 {current}/{total}',
'system_notice.release_400.eyebrow': '업데이트 완료', 'system_notice.release_notes.eyebrow': '업데이트 완료',
'system_notice.release_400.tag': '릴리스', 'system_notice.release_notes.headline': '이제 TREK이 직접 해내는 세 가지.',
'system_notice.release_400.headline': 'TREK 역사상 가장 큰 릴리스입니다.', 'system_notice.release_notes.intro':
'system_notice.release_400.intro': '자체 장소 API, 처음부터 끝까지 계획하는 로드트립, 그리고 다시 여러분의 손으로 돌아온 위치 기록.',
'TREK에 휴대폰과 책이 생겼습니다. 열아홉 명이 함께 만들었고, 보고된 버그 약 150개가 함께 정리되었습니다.', 'system_notice.release_notes.features_label': '이번 릴리스의 주역',
'system_notice.release_400.feature_mobile_title': 'TREK, 모바일로', 'system_notice.release_notes.features_aside': '이게 전부는 아닙니다',
'system_notice.release_400.feature_mobile_body': 'system_notice.release_notes.feature_places_title': 'TREK Places API',
'768px 아래는 이제 그 자체로 하나의 인터페이스입니다 — 글라스 독, 전용 시트, 전용 여행 플래너. 휴대폰에서 TREK을 열어보세요.', 'system_notice.release_notes.feature_places_body':
'system_notice.release_400.feature_studio_title': 'TREK Studio', '자체 장소 API를 직접 운영하는 최초의 오픈 소스 여행 플래너입니다. 7,360만 개의 장소를 매달 새로 구축합니다. 키도, 사용량 제한도 없습니다.',
'system_notice.release_400.feature_studio_badge': 'Beta', 'system_notice.release_notes.feature_roadtrip_title': '로드트립 애드온',
'system_notice.release_400.feature_studio_body': 'system_notice.release_notes.feature_roadtrip_body':
'Journey의 PDF가 사진 책 디자이너가 되었습니다. 부탁하면 책을 배치해 주고, 그다음엔 물러나 있습니다.', '로드트립 모드는 운전 자체를 계획합니다. 경로, 거리, 운전 시간, 경유지까지요. 애드온이라서 관리자가 켜기 전까지는 꺼져 있습니다.',
'system_notice.release_400.feature_vacay_title': 'Vacay, 나머지까지', 'system_notice.release_notes.feature_dawarich_title': 'Dawarich 연동',
'system_notice.release_400.feature_vacay_body': 'system_notice.release_notes.feature_dawarich_body':
'반차, 보상 휴가와 유연 근무일, 달력에 올라온 학교 방학 — 그리고 1월에 시작하지 않아도 되는 휴가 연도.', 'Google Timeline의 자체 호스팅 대안인 Dawarich를 이제 TREK 안에서 읽을 수 있습니다. TREK은 읽기만, 오직 읽기만 합니다. 다시 기록되는 것은 아무것도 없습니다.',
'system_notice.release_400.feature_places_title': '장소는 스스로 채우고, 파일은 밖으로', 'system_notice.release_notes.footnote': '그 밖에도 TREK 곳곳에 작은 변경이 많이 담겨 있습니다.',
'system_notice.release_400.feature_places_body': 'system_notice.release_notes.notes_label': '릴리스 노트',
'장소를 저장하기 전에 사진과 설명이 알아서 채워집니다. 그리고 업로드한 파일은 더 이상 TREK이 도는 디스크에 있지 않아도 됩니다.', 'system_notice.release_notes.note_eyebrow': '개발자의 한마디',
'system_notice.release_400.footnote': 'system_notice.release_notes.note_title': '여러분이 있어서 TREK을 계속 만듭니다.',
'그리고 이건 그중 네 가지입니다. 4.0.0에는 Collections와 Atlas부터 그 아래 서버 전체까지 수백 가지 변경이 더 담겨 있습니다.', 'system_notice.release_notes.note_body':
'system_notice.release_400.note_eyebrow': '개발자의 한마디', 'TREK은 제 여행을 위한 작은 도구로 시작했습니다. 여행을 더 잘 계획하고 싶어서 퇴근 후에 짬을 내 만들었습니다. 그 뒤로 사실상 한 번도 자라기를 멈춘 적이 없습니다. 여러분이 쓰는 거의 모든 기능은 풀타임 직장을 다니면서 늦은 밤에, 주말에, 기차 안에서 만들었고, 과연 누가 이걸 열어보기나 할까 조용히 생각하던 저녁도 많았습니다.',
'system_notice.release_400.note_title': 'TREK을 사용해 주셔서 감사합니다.', 'system_notice.release_notes.promise_label': '약속',
'system_notice.release_400.note_body': 'system_notice.release_notes.promise_lead': 'TREK은 영원히 무료입니다.',
'TREK은 제 여행을 위해 여가 시간에 만든 작은 도구로 시작했습니다. 지금도 그렇습니다. 저녁, 주말, 그리고 풀타임 직장 옆의 시간들.\n\n한동안은 저 혼자였습니다. 이제는 아닙니다 — 열아홉 명이 이번 릴리스를 함께 내보냈고, 수천 명이 별과 이슈, 번역과 풀 리퀘스트를 들고 찾아와 주셨습니다. 그 모든 것에 감사합니다.', 'system_notice.release_notes.promise_text':
'system_notice.release_400.promise_label': '약속', '모든 기능, 모든 업데이트를 모두에게. 유료 등급도, 구독도, 숨겨진 조건도 없습니다.',
'system_notice.release_400.promise_text': 'system_notice.release_notes.note_body_after':
'TREK의 오픈 소스 쪽은 영원히 무료입니다. 유료 등급도, 구독도, 숨겨진 조건도 없습니다. 약속드릴게요.', '그런데 여러분이 열어주셨습니다. 몇 달 만에 수천 명이 찾아와 주셨습니다. 별, 버그 보고, 제가 할 줄 모르는 언어로 된 번역, 한 번도 만난 적 없는 분들의 풀 리퀘스트까지. 지금도 매일 아침 가장 먼저 저장소를 확인하는데, 아직도 잘 실감이 나지 않습니다.',
'system_notice.release_400.note_body_after': 'system_notice.release_notes.note_closing': '함께해 주셔서 감사합니다. Maurice 드림',
'4.0.0에는 늦은 밤 몇 주가 들어갔습니다 — 휴대폰 화면, 책 디자이너, 서버 마이그레이션, 대부분 자정과 새벽 두 시 사이에 썼습니다. 불평은 아닙니다. 이걸 만드는 게 좋습니다. 다만 이 정도 규모의 릴리스가 여가 프로젝트에서 어떻게 나오는지에 대한 솔직한 답입니다.', 'system_notice.release_notes.support_lead':
'system_notice.release_400.note_closing': '함께해 주셔서 감사합니다.', 'TREK은 무료이고 앞으로도 그렇겠지만, 서버와 도메인, 수많은 늦은 밤은 무료가 아닙니다.',
'system_notice.release_400.note_signature': '— Maurice', 'system_notice.release_notes.support_text':
'system_notice.release_400.support_text': 'TREK이 여러분의 여행에 자리를 잡았다면, 커피 한 잔으로 다음 릴리스가 계속 나올 수 있게 도와주세요.',
'이걸 계속 굴러가게 하는 건 후원입니다 — 서버와 도메인, 그리고 이런 릴리스가 되는 늦은 밤들. TREK이 여러분에게 가치가 있다면, 커피 한 잔이 이어가는 가장 직접적인 방법입니다.', 'system_notice.release_notes.cta_bmc': 'Buy me a coffee',
'system_notice.release_400.cta_bmc': 'Buy me a coffee', 'system_notice.release_notes.cta_kofi': 'Ko-fi에서 후원하기',
'system_notice.release_400.cta_kofi': 'Ko-fi에서 후원하기',
}; };
export default system_notice; export default system_notice;
+35 -36
View File
@@ -54,41 +54,40 @@ const system_notice: TranslationStrings = {
'system_notice.v3014_whitespace_collision.title': 'Actie vereist: gebruikersaccountconflict', 'system_notice.v3014_whitespace_collision.title': 'Actie vereist: gebruikersaccountconflict',
'system_notice.v3014_whitespace_collision.body': 'system_notice.v3014_whitespace_collision.body':
'De 3.0.14-upgrade heeft één of meer conflicten in gebruikersnaam of e-mailadres gedetecteerd, veroorzaakt door spaties aan het begin of einde van opgeslagen waarden. Getroffen accounts zijn automatisch hernoemd. Controleer de serverlogboeken op regels die beginnen met **[migration] WHITESPACE COLLISION** om te achterhalen welke accounts moeten worden beoordeeld.', 'De 3.0.14-upgrade heeft één of meer conflicten in gebruikersnaam of e-mailadres gedetecteerd, veroorzaakt door spaties aan het begin of einde van opgeslagen waarden. Getroffen accounts zijn automatisch hernoemd. Controleer de serverlogboeken op regels die beginnen met **[migration] WHITESPACE COLLISION** om te achterhalen welke accounts moeten worden beoordeeld.',
// 4.0.0-releasemodal — links de release, rechts het woord van de maintainer // The release modal. One stable set of keys: each big release swaps the copy in place.
'system_notice.release_400.eyebrow': 'Update geïnstalleerd', 'system_notice.release_notes.eyebrow': 'Update geïnstalleerd',
'system_notice.release_400.tag': 'Release', 'system_notice.release_notes.headline': 'Drie dingen die TREK nu zelf doet.',
'system_notice.release_400.headline': 'De grootste release die TREK ooit heeft gehad.', 'system_notice.release_notes.intro':
'system_notice.release_400.intro': 'Een eigen API voor plaatsen, roadtrips van begin tot eind gepland en je locatiegeschiedenis weer in eigen hand.',
"TREK krijgt een telefoon en een boek. Negentien mensen schreven hieraan mee — en zo'n honderdvijftig gemelde bugs gingen mee.", 'system_notice.release_notes.features_label': 'De hoogtepunten',
'system_notice.release_400.feature_mobile_title': 'TREK wordt mobiel', 'system_notice.release_notes.features_aside': 'Lang niet alles',
'system_notice.release_400.feature_mobile_body': 'system_notice.release_notes.feature_places_title': 'TREK Places API',
'Alles onder 768px is nu een eigen interface — een glazen dock, eigen sheets, een eigen reisplanner. Open TREK op je telefoon.', 'system_notice.release_notes.feature_places_body':
'system_notice.release_400.feature_studio_title': 'TREK Studio', 'De eerste open source-reisplanner die zijn eigen API voor plaatsen host. 73,6 miljoen plaatsen, elke maand opnieuw opgebouwd. Geen sleutel, geen quotum.',
'system_notice.release_400.feature_studio_badge': 'Beta', 'system_notice.release_notes.feature_roadtrip_title': 'Roadtrip-addon',
'system_notice.release_400.feature_studio_body': 'system_notice.release_notes.feature_roadtrip_body':
'De Journey-PDF werd een fotoboekontwerper. Hij maakt de opmaak wanneer je erom vraagt en gaat daarna uit de weg.', 'De Roadtrip-modus plant de rit zelf: de route, de afstand, de rijtijd en de stops. Een addon die uit blijft tot een admin hem aanzet.',
'system_notice.release_400.feature_vacay_title': 'Vacay leert de rest', 'system_notice.release_notes.feature_dawarich_title': 'Dawarich-integratie',
'system_notice.release_400.feature_vacay_body': 'system_notice.release_notes.feature_dawarich_body':
'Halve dagen, compensatie- en flexdagen, schoolvakanties in het raster — en een verlofjaar dat niet in januari hoeft te beginnen.', 'Het zelfgehoste antwoord op Google Timeline, nu rechtstreeks leesbaar in TREK. TREK leest, en alleen dat. Er wordt nooit iets teruggeschreven.',
'system_notice.release_400.feature_places_title': 'Plaatsen tonen zichzelf, bestanden verhuizen', 'system_notice.release_notes.footnote': 'En daarnaast een lange lijst kleinere wijzigingen in de rest van TREK.',
'system_notice.release_400.feature_places_body': 'system_notice.release_notes.notes_label': 'Release notes',
"Foto's en een beschrijving vullen zichzelf in voordat je een plaats opslaat. En je uploads hoeven niet langer op de schijf te staan waarop TREK draait.", 'system_notice.release_notes.note_eyebrow': 'Een woord van de maintainer',
'system_notice.release_400.footnote': 'system_notice.release_notes.note_title': 'Jij bent de reden dat ik aan TREK blijf bouwen.',
'En dit zijn er vier. 4.0.0 bevat nog enkele honderden wijzigingen, van Collections en Atlas tot de hele server eronder.', 'system_notice.release_notes.note_body':
'system_notice.release_400.note_eyebrow': 'Een woord van de maintainer', 'TREK begon als een klein hulpmiddel voor mijn eigen reizen, geschreven na werktijd omdat ik ze beter wilde kunnen plannen. Eigenlijk is het nooit gestopt met groeien. Bijna alles wat je gebruikt, is gebouwd laat op de avond, in het weekend, in de trein, naast een fulltime baan, en op heel wat avonden vroeg ik me stilletjes af of iemand daarbuiten het ooit zou openen.',
'system_notice.release_400.note_title': 'Bedankt voor het gebruik van TREK.', 'system_notice.release_notes.promise_label': 'De belofte',
'system_notice.release_400.note_body': 'system_notice.release_notes.promise_lead': 'TREK blijft gratis, voor altijd.',
'TREK begon als een klein hulpmiddel voor mijn eigen reizen, geschreven in mijn vrije tijd. Dat is het nog steeds: avonden, weekenden, de uren naast een fulltime baan.\n\nEen tijdlang was ik de enige. Nu niet meer — negentien mensen maakten deze release, en duizenden van jullie kwamen erbij met sterren, issues, vertalingen en pull requests. Ik ben dankbaar voor elk stuk ervan.', 'system_notice.release_notes.promise_text':
'system_notice.release_400.promise_label': 'De belofte', 'Elke functie, elke update, voor iedereen. Geen betaalde versies, geen abonnementen, geen addertjes.',
'system_notice.release_400.promise_text': 'system_notice.release_notes.note_body_after':
'De open source-kant van TREK blijft gratis, voor altijd. Geen betaalde versies, geen abonnementen, geen addertjes. Beloofd.', 'En toen kwamen jullie. Binnen een paar maanden waren jullie met duizenden: sterren, bugmeldingen, vertalingen in talen die ik niet spreek, pull requests van mensen die ik nooit heb ontmoet. Nog altijd kijk ik elke ochtend als eerste in de repository, en het voelt nog steeds niet helemaal echt.',
'system_notice.release_400.note_body_after': 'system_notice.release_notes.note_closing': 'Bedankt dat je er bent. Groetjes, Maurice.',
'4.0.0 kostte weken aan late avonden — een mobiele app, een fotoboekontwerper, een servermigratie, het meeste geschreven tussen middernacht en twee uur. Geen klacht: ik bouw dit graag. Het is gewoon het eerlijke antwoord op hoe een release van deze omvang uit een vrijetijdsproject komt.', 'system_notice.release_notes.support_lead':
'system_notice.release_400.note_closing': 'Bedankt dat je er bent.', 'TREK is gratis en blijft dat ook, maar servers, domeinen en heel wat late avonden zijn dat niet.',
'system_notice.release_400.note_signature': '— Maurice', 'system_notice.release_notes.support_text':
'system_notice.release_400.support_text': 'Als TREK een plek in je reizen heeft verdiend, trakteer me dan op een kopje koffie en help zo de volgende release op weg.',
'Steun is wat dit draaiende houdt — servers, domeinen en de late avonden die uitmonden in releases als deze. Als TREK iets voor je waard is, is een kopje koffie de meest directe manier om het door te laten gaan.', 'system_notice.release_notes.cta_bmc': 'Buy me a coffee',
'system_notice.release_400.cta_bmc': 'Buy me a coffee', 'system_notice.release_notes.cta_kofi': 'Steun op Ko-fi',
'system_notice.release_400.cta_kofi': 'Steun op Ko-fi',
}; };
export default system_notice; export default system_notice;
+35 -36
View File
@@ -54,41 +54,40 @@ const system_notice: TranslationStrings = {
'system_notice.v3014_whitespace_collision.title': 'Wymagane działanie: konflikt konta użytkownika', 'system_notice.v3014_whitespace_collision.title': 'Wymagane działanie: konflikt konta użytkownika',
'system_notice.v3014_whitespace_collision.body': 'system_notice.v3014_whitespace_collision.body':
'Aktualizacja 3.0.14 wykryła jeden lub więcej konfliktów nazwy użytkownika lub adresu e-mail spowodowanych spacjami na początku lub końcu przechowywanych wartości. Dotknięte konta zostały automatycznie przemianowane. Sprawdź logi serwera pod kątem wierszy zaczynających się od **[migration] WHITESPACE COLLISION**, aby zidentyfikować konta wymagające przeglądu.', 'Aktualizacja 3.0.14 wykryła jeden lub więcej konfliktów nazwy użytkownika lub adresu e-mail spowodowanych spacjami na początku lub końcu przechowywanych wartości. Dotknięte konta zostały automatycznie przemianowane. Sprawdź logi serwera pod kątem wierszy zaczynających się od **[migration] WHITESPACE COLLISION**, aby zidentyfikować konta wymagające przeglądu.',
// 4.0.0 release modal — the release on the left, the note from the maintainer on the right // The release modal. One stable set of keys: each big release swaps the copy in place.
'system_notice.release_400.eyebrow': 'Aktualizacja zainstalowana', 'system_notice.release_notes.eyebrow': 'Aktualizacja zainstalowana',
'system_notice.release_400.tag': 'Wydanie', 'system_notice.release_notes.headline': 'Trzy rzeczy, które TREK robi teraz sam.',
'system_notice.release_400.headline': 'Największe wydanie w historii TREK.', 'system_notice.release_notes.intro':
'system_notice.release_400.intro': 'Własne API miejsc, podróże samochodowe zaplanowane od początku do końca i historia lokalizacji z powrotem w Twoich rękach.',
'TREK dostaje telefon i książkę. To wydanie napisało dziewiętnaście osób — a poszło z nim około stu pięćdziesięciu zgłoszonych błędów.', 'system_notice.release_notes.features_label': 'Najważniejsze nowości',
'system_notice.release_400.feature_mobile_title': 'TREK na telefonie', 'system_notice.release_notes.features_aside': 'To nie wszystko',
'system_notice.release_400.feature_mobile_body': 'system_notice.release_notes.feature_places_title': 'TREK Places API',
'Wszystko poniżej 768px ma teraz własny interfejs — szklany dok, własne panele, własny planer podróży. Otwórz TREK na telefonie.', 'system_notice.release_notes.feature_places_body':
'system_notice.release_400.feature_studio_title': 'TREK Studio', 'Pierwszy planer podróży open source, który hostuje własne API miejsc. 73,6 miliona miejsc, przebudowywanych co miesiąc. Bez klucza, bez limitów.',
'system_notice.release_400.feature_studio_badge': 'Beta', 'system_notice.release_notes.feature_roadtrip_title': 'Dodatek Podróż samochodowa',
'system_notice.release_400.feature_studio_body': 'system_notice.release_notes.feature_roadtrip_body':
'PDF z Journey stał się projektantem fotoksiążki. Układa książkę, kiedy go o to poprosisz, a potem schodzi z drogi.', 'Tryb podróży samochodowej planuje samą jazdę: trasę, jej długość, czas jazdy i przystanki. To dodatek, wyłączony, dopóki administrator go nie włączy.',
'system_notice.release_400.feature_vacay_title': 'Vacay uczy się reszty', 'system_notice.release_notes.feature_dawarich_title': 'Integracja z Dawarich',
'system_notice.release_400.feature_vacay_body': 'system_notice.release_notes.feature_dawarich_body':
'Pół dnia, dni wolne za nadgodziny i dni flex, ferie szkolne na siatce — i rok urlopowy, który nie musi zaczynać się w styczniu.', 'Samodzielnie hostowana odpowiedź na Google Timeline, teraz dostępna w TREK. TREK tylko odczytuje, nic więcej. Nigdy niczego nie zapisuje z powrotem.',
'system_notice.release_400.feature_places_title': 'Miejsca się pokazują, pliki wyprowadzają', 'system_notice.release_notes.footnote': 'Do tego długa lista mniejszych zmian w całej reszcie TREK.',
'system_notice.release_400.feature_places_body': 'system_notice.release_notes.notes_label': 'Notatki do wydania',
'Zdjęcia i opis uzupełniają się same, zanim zapiszesz miejsce. A Twoje pliki nie muszą już leżeć na dysku, na którym działa TREK.', 'system_notice.release_notes.note_eyebrow': 'Słowo od autora',
'system_notice.release_400.footnote': 'system_notice.release_notes.note_title': 'To dzięki wam wciąż rozwijam TREK.',
'A to tylko cztery z nich. 4.0.0 niesie kilkaset kolejnych zmian, od Collections i Atlas po cały serwer pod spodem.', 'system_notice.release_notes.note_body':
'system_notice.release_400.note_eyebrow': 'Słowo od autora', 'TREK zaczął się jako małe narzędzie na moje własne podróże, pisane po pracy, bo chciałem wygodniej je planować. I tak naprawdę nigdy nie przestał rosnąć. Prawie wszystko, z czego korzystacie, powstało późno w nocy, w weekendy, w pociągach, obok pracy na pełny etat, i było wiele wieczorów, kiedy po cichu zastanawiałem się, czy ktokolwiek go kiedyś otworzy.',
'system_notice.release_400.note_title': 'Dziękuję, że korzystasz z TREK.', 'system_notice.release_notes.promise_label': 'Obietnica',
'system_notice.release_400.note_body': 'system_notice.release_notes.promise_lead': 'TREK pozostanie darmowy, na zawsze.',
'TREK zaczął się jako małe narzędzie na moje własne podróże, pisane po godzinach. Nadal takie jest: wieczory, weekendy, godziny obok pracy na pełny etat.\n\nPrzez jakiś czas byłem w tym sam. Już nie — to wydanie dowiozło dziewiętnaście osób, a tysiące z was przyszły z gwiazdkami, zgłoszeniami, tłumaczeniami i pull requestami. Jestem wdzięczny za każdy kawałek tego.', 'system_notice.release_notes.promise_text':
'system_notice.release_400.promise_label': 'Obietnica', 'Każda funkcja, każda aktualizacja, dla wszystkich. Bez płatnych wersji, bez subskrypcji, bez haczyków.',
'system_notice.release_400.promise_text': 'system_notice.release_notes.note_body_after':
'Otwartoźródłowa część TREK pozostaje darmowa, na zawsze. Bez płatnych wersji, bez subskrypcji, bez haczyków. Obiecuję.', 'A potem go otworzyliście. W ciągu kilku miesięcy były was tysiące: gwiazdki, zgłoszenia błędów, tłumaczenia na języki, których nie znam, pull requesty od ludzi, których nigdy nie spotkałem. Wciąż każdego ranka najpierw zaglądam do repozytorium i wciąż nie do końca w to wierzę.',
'system_notice.release_400.note_body_after': 'system_notice.release_notes.note_closing': 'Dziękuję, że tu jesteście. Pozdrawiam, Maurice.',
'4.0.0 kosztowało tygodnie nocnych sesji — aplikacja na telefon, projektant książek, migracja serwera, większość pisana między północą a drugą. To nie skarga: uwielbiam to budować. To po prostu szczera odpowiedź na to, jak z projektu po godzinach wychodzi wydanie tej wielkości.', 'system_notice.release_notes.support_lead':
'system_notice.release_400.note_closing': 'Dziękuję, że tu jesteś.', 'TREK jest darmowy i zawsze taki będzie, ale serwery, domeny i wiele zarwanych nocy już nie.',
'system_notice.release_400.note_signature': '— Maurice', 'system_notice.release_notes.support_text':
'system_notice.release_400.support_text': 'Jeśli TREK zasłużył na miejsce w Twoich podróżach, postaw mi kawę i pomóż, żeby powstało kolejne wydanie.',
'Wsparcie jest tym, co to wszystko utrzymuje — serwery, domeny i nocne sesje, które zamieniają się w wydania takie jak to. Jeśli TREK jest dla Ciebie coś wart, kawa to najprostszy sposób, żeby to podtrzymać.', 'system_notice.release_notes.cta_bmc': 'Buy me a coffee',
'system_notice.release_400.cta_bmc': 'Buy me a coffee', 'system_notice.release_notes.cta_kofi': 'Wesprzyj na Ko-fi',
'system_notice.release_400.cta_kofi': 'Wesprzyj na Ko-fi',
}; };
export default system_notice; export default system_notice;
+35 -36
View File
@@ -54,41 +54,40 @@ const system_notice: TranslationStrings = {
'system_notice.v3014_whitespace_collision.title': 'Требуется действие: конфликт учётных записей', 'system_notice.v3014_whitespace_collision.title': 'Требуется действие: конфликт учётных записей',
'system_notice.v3014_whitespace_collision.body': 'system_notice.v3014_whitespace_collision.body':
'Обновление 3.0.14 обнаружило один или несколько конфликтов имён пользователей или адресов электронной почты, вызванных ведущими или завершающими пробелами в сохранённых значениях. Затронутые учётные записи были автоматически переименованы. Проверьте логи сервера на строки, начинающиеся с **[migration] WHITESPACE COLLISION**, чтобы определить учётные записи, требующие проверки.', 'Обновление 3.0.14 обнаружило один или несколько конфликтов имён пользователей или адресов электронной почты, вызванных ведущими или завершающими пробелами в сохранённых значениях. Затронутые учётные записи были автоматически переименованы. Проверьте логи сервера на строки, начинающиеся с **[migration] WHITESPACE COLLISION**, чтобы определить учётные записи, требующие проверки.',
// 4.0.0 release modal — the release on the left, the note from the maintainer on the right // The release modal. One stable set of keys: each big release swaps the copy in place.
'system_notice.release_400.eyebrow': 'Обновление установлено', 'system_notice.release_notes.eyebrow': 'Обновление установлено',
'system_notice.release_400.tag': 'Релиз', 'system_notice.release_notes.headline': 'Три вещи, которые TREK теперь делает сам.',
'system_notice.release_400.headline': 'Самый большой релиз в истории TREK.', 'system_notice.release_notes.intro':
'system_notice.release_400.intro': 'Собственный API мест, автопутешествия, продуманные от старта до финиша, и история перемещений, которая снова принадлежит вам.',
'TREK получает телефон и книгу. Этот релиз написали девятнадцать человек — и вместе с ним закрылись около ста пятидесяти присланных багов.', 'system_notice.release_notes.features_label': 'Главные новинки',
'system_notice.release_400.feature_mobile_title': 'TREK на телефоне', 'system_notice.release_notes.features_aside': 'И это далеко не всё',
'system_notice.release_400.feature_mobile_body': 'system_notice.release_notes.feature_places_title': 'TREK Places API',
'Всё, что уже 768px, теперь отдельный интерфейс — стеклянный док, свои шторки, свой планировщик поездок. Откройте TREK на телефоне.', 'system_notice.release_notes.feature_places_body':
'system_notice.release_400.feature_studio_title': 'TREK Studio', 'Первый планировщик путешествий с открытым исходным кодом, у которого есть собственный API мест. 73,6 миллиона мест, база заново собирается каждый месяц. Никаких ключей, никаких квот.',
'system_notice.release_400.feature_studio_badge': 'Beta', 'system_notice.release_notes.feature_roadtrip_title': 'Дополнение «Автопутешествие»',
'system_notice.release_400.feature_studio_body': 'system_notice.release_notes.feature_roadtrip_body':
'PDF из Journey превратился в конструктор фотокниги. Он собирает книгу, когда вы попросите, и дальше не мешает.', 'Режим автопутешествия планирует саму дорогу: маршрут, расстояние, часы за рулём и остановки. Это дополнение, и оно выключено, пока администратор его не включит.',
'system_notice.release_400.feature_vacay_title': 'Vacay освоил остальное', 'system_notice.release_notes.feature_dawarich_title': 'Интеграция с Dawarich',
'system_notice.release_400.feature_vacay_body': 'system_notice.release_notes.feature_dawarich_body':
'Полдня, отгулы и гибкие дни, школьные каникулы в сетке — и отпускной год, который не обязан начинаться в январе.', 'Альтернатива Google Timeline на вашем собственном сервере, и теперь её данные видны прямо в TREK. TREK читает, и только читает. Обратно не записывается ничего и никогда.',
'system_notice.release_400.feature_places_title': 'Места показывают себя, файлы съезжают', 'system_notice.release_notes.footnote': 'Плюс длинный список небольших изменений во всём остальном TREK.',
'system_notice.release_400.feature_places_body': 'system_notice.release_notes.notes_label': 'Заметки к релизу',
'Фото и описание подставляются сами ещё до того, как вы сохраните место. А загруженные файлы больше не обязаны лежать на диске, где работает TREK.', 'system_notice.release_notes.note_eyebrow': 'Слово от мейнтейнера',
'system_notice.release_400.footnote': 'system_notice.release_notes.note_title': 'Именно ради вас я продолжаю развивать TREK.',
'И это только четыре из них. В 4.0.0 ещё несколько сотен изменений — от Collections и Atlas до всего сервера под ними.', 'system_notice.release_notes.note_body':
'system_notice.release_400.note_eyebrow': 'Слово от мейнтейнера', 'TREK начинался как маленький инструмент для моих собственных поездок: я писал его после работы, потому что хотел планировать их удобнее. С тех пор он, по сути, так и не перестал расти. Почти всё, чем вы пользуетесь, создано поздно ночью, по выходным, в поездах, параллельно с основной работой, и было немало вечеров, когда я тихо сомневался, откроет ли его вообще хоть кто-нибудь.',
'system_notice.release_400.note_title': 'Спасибо, что пользуетесь TREK.', 'system_notice.release_notes.promise_label': 'Обещание',
'system_notice.release_400.note_body': 'system_notice.release_notes.promise_lead': 'TREK остаётся бесплатным навсегда.',
'TREK начинался как маленький инструмент для моих собственных поездок, написанный в свободное время. Таким он и остался: вечера, выходные, часы рядом с основной работой.\n\nКакое-то время я был один. Уже нет — этот релиз выпустили девятнадцать человек, а тысячи из вас пришли со звёздами, issue, переводами и пул-реквестами. Я благодарен за каждую часть этого.', 'system_notice.release_notes.promise_text':
'system_notice.release_400.promise_label': 'Обещание', 'Все функции и все обновления, для всех. Никаких платных тарифов, никаких подписок, никаких подвохов.',
'system_notice.release_400.promise_text': 'system_notice.release_notes.note_body_after':
'Открытая часть TREK остаётся бесплатной навсегда. Никаких платных тарифов, никаких подписок, никаких подвохов. Обещаю.', 'А потом его открыли вы. За несколько месяцев вас стали тысячи: звёзды, отчёты об ошибках, переводы на языки, которыми я не владею, пул-реквесты от людей, с которыми я ни разу не встречался. Я до сих пор каждое утро первым делом заглядываю в репозиторий, и мне всё ещё не до конца верится, что это происходит.',
'system_notice.release_400.note_body_after': 'system_notice.release_notes.note_closing': 'Спасибо, что вы здесь. Ваш Maurice.',
'4.0.0 стоил недель поздних ночей — приложение для телефона, конструктор книги, миграция сервера, и почти всё это написано между полуночью и двумя. Это не жалоба: мне нравится это делать. Просто честный ответ на то, как релиз такого размера выходит из проекта в свободное время.', 'system_notice.release_notes.support_lead':
'system_notice.release_400.note_closing': 'Спасибо, что вы здесь.', 'TREK бесплатен и таким останется, а вот серверы, домены и бесконечные поздние вечера бесплатными не бывают.',
'system_notice.release_400.note_signature': '— Maurice', 'system_notice.release_notes.support_text':
'system_notice.release_400.support_text': 'Если TREK заслужил место в ваших поездках, угостите меня кофе и помогите выпустить следующий релиз.',
'Поддержка — это то, на чём всё держится: серверы, домены и те поздние ночи, из которых получаются такие релизы. Если TREK для вас чего-то стоит, кофе — самый прямой способ помочь.', 'system_notice.release_notes.cta_bmc': 'Buy me a coffee',
'system_notice.release_400.cta_bmc': 'Buy me a coffee', 'system_notice.release_notes.cta_kofi': 'Поддержать на Ko-fi',
'system_notice.release_400.cta_kofi': 'Поддержать на Ko-fi',
}; };
export default system_notice; export default system_notice;
+35 -36
View File
@@ -54,41 +54,40 @@ const system_notice: TranslationStrings = {
'system_notice.pager.counter': '{current} / {total}', 'system_notice.pager.counter': '{current} / {total}',
'system_notice.pager.goto': 'Gå till meddelandet {n}', 'system_notice.pager.goto': 'Gå till meddelandet {n}',
'system_notice.pager.position': 'Meddlenade {current} av {total}', 'system_notice.pager.position': 'Meddlenade {current} av {total}',
// 4.0.0 release modal — the release on the left, the note from the maintainer on the right // The release modal. One stable set of keys: each big release swaps the copy in place.
'system_notice.release_400.eyebrow': 'Uppdatering klar', 'system_notice.release_notes.eyebrow': 'Uppdatering klar',
'system_notice.release_400.tag': 'Utgåva', 'system_notice.release_notes.headline': 'Tre saker som TREK nu klarar på egen hand.',
'system_notice.release_400.headline': 'Den största utgåvan TREK har haft.', 'system_notice.release_notes.intro':
'system_notice.release_400.intro': 'Ett eget API för platser, bilresor planerade från start till mål och din platshistorik tillbaka i dina händer.',
'TREK får en telefon, och en bok. Nitton personer skrev den här — och ungefär hundrafemtio rapporterade fel följde med.', 'system_notice.release_notes.features_label': 'Höjdpunkterna',
'system_notice.release_400.feature_mobile_title': 'TREK blir mobilt', 'system_notice.release_notes.features_aside': 'Långt ifrån allt',
'system_notice.release_400.feature_mobile_body': 'system_notice.release_notes.feature_places_title': 'TREK Places API',
'Allt under 768px är ett eget gränssnitt nu — en dock i glas, egna paneler, en egen resplanerare. Öppna TREK i telefonen.', 'system_notice.release_notes.feature_places_body':
'system_notice.release_400.feature_studio_title': 'TREK Studio', 'Den första resplaneraren med öppen källkod som driver sitt eget API för platser. 73,6 miljoner platser som byggs om varje månad. Ingen nyckel, ingen kvot.',
'system_notice.release_400.feature_studio_badge': 'Beta', 'system_notice.release_notes.feature_roadtrip_title': 'Tillägget Bilresa',
'system_notice.release_400.feature_studio_body': 'system_notice.release_notes.feature_roadtrip_body':
'Journey-PDF:en blev en fotoboksdesigner. Den lägger ut boken när du ber om det, och håller sig sedan undan.', 'Bilreseläget planerar själva körningen: rutten, sträckan, körtiden och stoppen. Ett tillägg som är avstängt tills en administratör slår på det.',
'system_notice.release_400.feature_vacay_title': 'Vacay lär sig resten', 'system_notice.release_notes.feature_dawarich_title': 'Dawarich-integration',
'system_notice.release_400.feature_vacay_body': 'system_notice.release_notes.feature_dawarich_body':
'Halvdagar, komp- och flexdagar, skollov i rutnätet — och ett semesterår som inte måste börja i januari.', 'Det självhostade svaret på Google Timeline, nu läsbart direkt i TREK. TREK läser, och bara läser. Ingenting skrivs någonsin tillbaka.',
'system_notice.release_400.feature_places_title': 'Platser visar sig, filer flyttar ut', 'system_notice.release_notes.footnote': 'Dessutom en lång rad mindre ändringar i resten av TREK.',
'system_notice.release_400.feature_places_body': 'system_notice.release_notes.notes_label': 'Versionsnyheter',
'Bilder och en beskrivning fyller i sig själva innan du sparar en plats. Och dina uppladdningar behöver inte längre ligga på disken TREK kör på.', 'system_notice.release_notes.note_eyebrow': 'Ett ord från utvecklaren',
'system_notice.release_400.footnote': 'system_notice.release_notes.note_title': 'Du är anledningen till att jag fortsätter bygga TREK.',
'Och det här är fyra av dem. 4.0.0 innehåller flera hundra ytterligare ändringar, från Collections och Atlas till hela servern under.', 'system_notice.release_notes.note_body':
'system_notice.release_400.note_eyebrow': 'Ett ord från utvecklaren', 'TREK började som ett litet verktyg för mina egna resor, skrivet efter jobbet för att jag ville ha ett bättre sätt att planera dem. Det har egentligen aldrig slutat växa. Nästan allt du använder byggdes sent på nätterna, på helger, på tåg, vid sidan av ett heltidsjobb, och många kvällar undrade jag tyst för mig själv om någon där ute någonsin skulle öppna det.',
'system_notice.release_400.note_title': 'Tack för att du använder TREK.', 'system_notice.release_notes.promise_label': 'Löftet',
'system_notice.release_400.note_body': 'system_notice.release_notes.promise_lead': 'TREK förblir gratis, för alltid.',
'TREK började som ett litet verktyg för mina egna resor, skrivet på fritiden. Det är det fortfarande: kvällar, helger, timmarna vid sidan av ett heltidsjobb.\n\nEtt tag var det bara jag. Inte längre — nitton personer levererade den här utgåvan, och tusentals av er kom med stjärnor, ärenden, översättningar och pull requests. Jag är tacksam för varenda del av det.', 'system_notice.release_notes.promise_text':
'system_notice.release_400.promise_label': 'Löftet', 'Varje funktion, varje uppdatering, för alla. Inga betalnivåer, inga prenumerationer, inga förbehåll.',
'system_notice.release_400.promise_text': 'system_notice.release_notes.note_body_after':
'Den öppna delen av TREK är gratis, för alltid. Inga betalnivåer, inga prenumerationer, inga förbehåll. Lovat.', 'Och sedan gjorde ni det. Inom några månader var ni tusentals: stjärnor, felrapporter, översättningar till språk jag inte talar, pull requests från människor jag aldrig har träffat. Jag kollar fortfarande repot varje morgon innan jag gör något annat, och det känns ännu inte riktigt verkligt.',
'system_notice.release_400.note_body_after': 'system_notice.release_notes.note_closing': 'Tack för att du är här. Hälsningar, Maurice.',
'4.0.0 tog veckor av sena nätter — en mobilapp, en fotoboksdesigner, en servermigrering, det mesta skrivet mellan midnatt och två. Inget gnäll: jag älskar att bygga det här. Det är bara det ärliga svaret på hur en utgåva av den här storleken kommer ur ett fritidsprojekt.', 'system_notice.release_notes.support_lead':
'system_notice.release_400.note_closing': 'Tack för att du är här.', 'TREK är gratis och kommer alltid att vara det, men servrar, domäner och många sena nätter är det inte.',
'system_notice.release_400.note_signature': '— Maurice', 'system_notice.release_notes.support_text':
'system_notice.release_400.support_text': 'Om TREK har förtjänat en plats på dina resor, så bjud mig gärna på en kaffe och hjälp till att nästa utgåva blir av.',
'Stödet är det som håller igång det här — servrar, domäner och de sena nätter som blir till utgåvor som den här. Om TREK är värt något för dig är en kaffe det mest direkta sättet att hålla det vid liv.', 'system_notice.release_notes.cta_bmc': 'Buy me a coffee',
'system_notice.release_400.cta_bmc': 'Buy me a coffee', 'system_notice.release_notes.cta_kofi': 'Stöd på Ko-fi',
'system_notice.release_400.cta_kofi': 'Stöd på Ko-fi',
}; };
export default system_notice; export default system_notice;
+35 -35
View File
@@ -54,40 +54,40 @@ const system_notice: TranslationStrings = {
'system_notice.pager.counter': '{current} / {total}', 'system_notice.pager.counter': '{current} / {total}',
'system_notice.pager.goto': '{n}. bildirime git', 'system_notice.pager.goto': '{n}. bildirime git',
'system_notice.pager.position': '{total} Bildirimden {current}.', 'system_notice.pager.position': '{total} Bildirimden {current}.',
'system_notice.release_400.eyebrow': 'Güncelleme yüklendi', 'system_notice.release_notes.eyebrow': 'Güncelleme yüklendi',
'system_notice.release_400.tag': 'Sürüm', 'system_notice.release_notes.headline': "TREK'in artık kendi başına yaptığı üç şey.",
'system_notice.release_400.headline': "TREK'in bugüne kadarki en büyük sürümü.", 'system_notice.release_notes.intro':
'system_notice.release_400.intro': "Kendi yer API'si, baştan sona planlanan yol gezileri ve yeniden senin elinde olan konum geçmişin.",
'TREK bir telefon ve bir kitap kazanıyor. Bunu on dokuz kişi yazdı — ve yaklaşık yüz elli bildirilen hata da onunla birlikte gitti.', 'system_notice.release_notes.features_label': 'Öne çıkanlar',
'system_notice.release_400.feature_mobile_title': 'TREK mobile geçiyor', 'system_notice.release_notes.features_aside': 'Hepsi bu kadar değil',
'system_notice.release_400.feature_mobile_body': 'system_notice.release_notes.feature_places_title': 'TREK Places API',
"768px altındaki her şey artık kendi arayüzü — cam bir dock, kendi panelleri, kendi seyahat planlayıcısı. TREK'i telefonunda aç.", 'system_notice.release_notes.feature_places_body':
'system_notice.release_400.feature_studio_title': 'TREK Studio', "Kendi yer API'sini barındıran ilk açık kaynak seyahat planlayıcısı. 73,6 milyon yer, her ay yeniden oluşturuluyor. Anahtar yok, kota yok.",
'system_notice.release_400.feature_studio_badge': 'Beta', 'system_notice.release_notes.feature_roadtrip_title': 'Yol gezisi eklentisi',
'system_notice.release_400.feature_studio_body': 'system_notice.release_notes.feature_roadtrip_body':
"Journey PDF'i bir fotoğraf kitabı tasarımcısına dönüştü. İstediğinde kitabı kendisi düzenler, sonra yoldan çekilir.", 'Yol gezisi modu sürüşün kendisini planlar: rotayı, mesafeyi, süreyi ve durakları. Bir eklentidir ve bir yönetici açana kadar kapalı kalır.',
'system_notice.release_400.feature_vacay_title': 'Vacay gerisini öğreniyor', 'system_notice.release_notes.feature_dawarich_title': 'Dawarich entegrasyonu',
'system_notice.release_400.feature_vacay_body': 'system_notice.release_notes.feature_dawarich_body':
'Yarım günler, telafi ve esnek günler, takvimde okul tatilleri — ve ocakta başlamak zorunda olmayan bir izin yılı.', "Google Timeline'ın kendi sunucunda çalışan alternatifi, artık TREK içinden okunabiliyor. TREK okur, yalnızca okur. Geriye hiçbir zaman hiçbir şey yazılmaz.",
'system_notice.release_400.feature_places_title': 'Yerler kendini gösterir, dosyalar taşınır', 'system_notice.release_notes.footnote':
'system_notice.release_400.feature_places_body': "Ayrıca TREK'in geri kalanına yayılmış, daha küçük değişikliklerden oluşan uzun bir liste var.",
"Bir yeri kaydetmeden önce resimler ve açıklama kendiliğinden dolar. Ve yüklemelerinin artık TREK'in çalıştığı diskte durması gerekmiyor.", 'system_notice.release_notes.notes_label': 'Sürüm notları',
'system_notice.release_400.footnote': 'system_notice.release_notes.note_eyebrow': 'Geliştiriciden bir not',
"Ve bunlar onlardan sadece dördü. 4.0.0, Collections ve Atlas'tan alttaki sunucunun tamamına kadar birkaç yüz değişiklik daha taşıyor.", 'system_notice.release_notes.note_title': "TREK'i geliştirmeye devam etmemin sebebi sensin.",
'system_notice.release_400.note_eyebrow': 'Geliştiriciden bir not', 'system_notice.release_notes.note_body':
'system_notice.release_400.note_title': "TREK'i kullandığın için teşekkürler.", 'TREK, kendi seyahatlerim için küçük bir araç olarak başladı. Onları daha iyi planlamak istediğim için iş çıkışlarında yazıyordum. O günden beri de büyümeyi hiç tam olarak bırakmadı. Kullandığın neredeyse her şey gece geç saatlerde, hafta sonlarında, trenlerde, tam zamanlı bir işin yanında yapıldı ve birinin onu bir gün gerçekten açıp açmayacağını içten içe merak ettiğim çok akşam oldu.',
'system_notice.release_400.note_body': 'system_notice.release_notes.promise_label': 'Söz',
"TREK, boş zamanlarımda kendi seyahatlerim için yazdığım küçük bir araç olarak başladı. Hâlâ da öyle: akşamlar, hafta sonları, tam zamanlı bir işin yanındaki saatler.\n\nBir süre yalnızca bendim. Artık değil — bu sürümü on dokuz kişi çıkardı ve binlerceniz yıldızlarla, issue'larla, çevirilerle ve pull request'lerle geldiniz. Her biri için minnettarım.", 'system_notice.release_notes.promise_lead': 'TREK sonsuza dek ücretsiz kalacak.',
'system_notice.release_400.promise_label': 'Söz', 'system_notice.release_notes.promise_text':
'system_notice.release_400.promise_text': 'Her özellik, her güncelleme, herkes için. Ücretli paket yok, abonelik yok, gizli şart yok.',
"TREK'in açık kaynak tarafı sonsuza dek ücretsiz kalıyor. Ücretli paket yok, abonelik yok, gizli şart yok. Söz.", 'system_notice.release_notes.note_body_after':
'system_notice.release_400.note_body_after': "Sonra sizler açtınız. Birkaç ay içinde sayınız binleri buldu: yıldızlar, hata bildirimleri, konuşmadığım dillere çeviriler, hiç tanışmadığım insanlardan pull request'ler. Hâlâ her sabah ilk iş repoya bakıyorum ve bu hâlâ tam olarak gerçekmiş gibi gelmiyor.",
'4.0.0, haftalarca süren geç geceler demekti — bir telefon uygulaması, bir kitap tasarımcısı, bir sunucu taşıması, çoğu gece yarısı ile ikisi arasında yazıldı. Şikâyet değil: bunu geliştirmeyi seviyorum. Sadece bu büyüklükte bir sürümün boş zaman projesinden nasıl çıktığının dürüst cevabı.', 'system_notice.release_notes.note_closing': 'Burada olduğun için teşekkür ederim. Sevgiler, Maurice.',
'system_notice.release_400.note_closing': 'Burada olduğun için teşekkür ederim.', 'system_notice.release_notes.support_lead':
'system_notice.release_400.note_signature': '— Maurice', 'TREK ücretsiz ve hep öyle kalacak, ama sunucular, alan adları ve bir sürü geç gece ücretsiz değil.',
'system_notice.release_400.support_text': 'system_notice.release_notes.support_text':
'Bunu ayakta tutan şey destek — sunucular, alan adları ve böyle sürümlere dönüşen geç geceler. TREK senin için bir şey ifade ediyorsa, bir kahve bunu sürdürmenin en doğrudan yolu.', 'TREK seyahatlerinde kendine bir yer edindiyse, bana bir kahve ısmarla ve bir sonraki sürümün gelmesine yardım et.',
'system_notice.release_400.cta_bmc': 'Buy me a coffee', 'system_notice.release_notes.cta_bmc': 'Buy me a coffee',
'system_notice.release_400.cta_kofi': "Ko-fi'de Destek Ol", 'system_notice.release_notes.cta_kofi': "Ko-fi'de Destek Ol",
}; };
export default system_notice; export default system_notice;
+35 -36
View File
@@ -54,41 +54,40 @@ const system_notice: TranslationStrings = {
'system_notice.v3014_whitespace_collision.title': 'Потрібна дія: конфлікт облікового запису користувача', 'system_notice.v3014_whitespace_collision.title': 'Потрібна дія: конфлікт облікового запису користувача',
'system_notice.v3014_whitespace_collision.body': 'system_notice.v3014_whitespace_collision.body':
'Оновлення 3.0.14 виявило один або кілька конфліктів імен користувачів або електронних адрес, спричинених початковими або кінцевими пробілами в збережених облікових записах. Уражені облікові записи було автоматично перейменовано. Перевірте журнали сервера на рядки, що починаються з **[migration] WHITESPACE COLLISION**, щоб визначити, які облікові записи потребують перевірки.', 'Оновлення 3.0.14 виявило один або кілька конфліктів імен користувачів або електронних адрес, спричинених початковими або кінцевими пробілами в збережених облікових записах. Уражені облікові записи було автоматично перейменовано. Перевірте журнали сервера на рядки, що починаються з **[migration] WHITESPACE COLLISION**, щоб визначити, які облікові записи потребують перевірки.',
// 4.0.0 release modal — the release on the left, the note from the maintainer on the right // The release modal. One stable set of keys: each big release swaps the copy in place.
'system_notice.release_400.eyebrow': 'Оновлення встановлено', 'system_notice.release_notes.eyebrow': 'Оновлення встановлено',
'system_notice.release_400.tag': 'Реліз', 'system_notice.release_notes.headline': 'Три речі, які TREK тепер робить сам.',
'system_notice.release_400.headline': 'Найбільший реліз в історії TREK.', 'system_notice.release_notes.intro':
'system_notice.release_400.intro': 'Власний API місць, автоподорожі, сплановані від початку до кінця, і ваша історія місцезнаходжень знову у ваших руках.',
'TREK отримує телефон і книгу. Цей реліз написали дев’ятнадцять людей — і разом з ним закрилися близько ста п’ятдесяти надісланих багів.', 'system_notice.release_notes.features_label': 'Головні новинки',
'system_notice.release_400.feature_mobile_title': 'TREK на телефоні', 'system_notice.release_notes.features_aside': 'І це далеко не все',
'system_notice.release_400.feature_mobile_body': 'system_notice.release_notes.feature_places_title': 'TREK Places API',
'Усе, що вужче за 768px, тепер окремий інтерфейс — скляний док, власні шторки, власний планувальник поїздок. Відкрийте TREK на телефоні.', 'system_notice.release_notes.feature_places_body':
'system_notice.release_400.feature_studio_title': 'TREK Studio', 'Перший планувальник подорожей з відкритим кодом, який має власний API місць. 73,6 мільйона місць, щомісяця зібраних наново. Без ключа, без квот.',
'system_notice.release_400.feature_studio_badge': 'Beta', 'system_notice.release_notes.feature_roadtrip_title': 'Доповнення «Автоподорож»',
'system_notice.release_400.feature_studio_body': 'system_notice.release_notes.feature_roadtrip_body':
'PDF із Journey став конструктором фотокниги. Він збирає книгу, коли ви попросите, і далі не заважає.', 'Режим автоподорожі планує саму поїздку: маршрут, відстань, години в дорозі та зупинки. Це доповнення, і воно вимкнене, доки його не ввімкне адміністратор.',
'system_notice.release_400.feature_vacay_title': 'Vacay освоїв решту', 'system_notice.release_notes.feature_dawarich_title': 'Інтеграція з Dawarich',
'system_notice.release_400.feature_vacay_body': 'system_notice.release_notes.feature_dawarich_body':
'Півдня, відгули та гнучкі дні, шкільні канікули в сітці — і відпускний рік, який не мусить починатися в січні.', 'Self-hosted альтернатива Google Timeline, яку тепер можна читати прямо в TREK. TREK читає, і тільки читає. Назад нічого ніколи не записується.',
'system_notice.release_400.feature_places_title': 'Місця показують себе, файли з’їжджають', 'system_notice.release_notes.footnote': 'А також довгий список дрібніших змін по всьому TREK.',
'system_notice.release_400.feature_places_body': 'system_notice.release_notes.notes_label': 'Нотатки до релізу',
'Фото й опис підставляються самі ще до того, як ви збережете місце. А завантажені файли більше не мусять лежати на диску, де працює TREK.', 'system_notice.release_notes.note_eyebrow': 'Слово від мейнтейнера',
'system_notice.release_400.footnote': 'system_notice.release_notes.note_title': 'Саме заради вас я далі розвиваю TREK.',
'І це лише чотири з них. У 4.0.0 ще кілька сотень змін — від Collections і Atlas до всього сервера під ними.', 'system_notice.release_notes.note_body':
'system_notice.release_400.note_eyebrow': 'Слово від мейнтейнера', 'TREK починався як маленький інструмент для моїх власних поїздок, який я писав після роботи, бо хотів планувати їх краще. І відтоді він, власне, не переставав рости. Майже все, чим ви користуєтесь, створено пізно вночі, на вихідних, у поїздах, поруч з основною роботою, і було чимало вечорів, коли я тихо питав себе, чи хтось узагалі колись його відкриє.',
'system_notice.release_400.note_title': 'Дякую, що користуєтесь TREK.', 'system_notice.release_notes.promise_label': 'Обіцянка',
'system_notice.release_400.note_body': 'system_notice.release_notes.promise_lead': 'TREK залишиться безкоштовним назавжди.',
'TREK починався як маленький інструмент для моїх власних поїздок, написаний у вільний час. Таким і залишився: вечори, вихідні, години поруч з основною роботою.\n\nЯкийсь час я був сам. Уже ні — цей реліз випустили дев’ятнадцять людей, а тисячі з вас прийшли із зірками, issue, перекладами та пул-реквестами. Я вдячний за кожну частину цього.', 'system_notice.release_notes.promise_text':
'system_notice.release_400.promise_label': 'Обіцянка', 'Кожна функція, кожне оновлення, для всіх. Жодних платних тарифів, жодних підписок, жодних підводних каменів.',
'system_notice.release_400.promise_text': 'system_notice.release_notes.note_body_after':
'Відкрита частина TREK залишається безкоштовною назавжди. Жодних платних тарифів, жодних підписок, жодних підводних каменів. Обіцяю.', 'А потім його відкрили ви. За кілька місяців вас стали тисячі: зірки, звіти про баги, переклади мовами, якими я не володію, пул-реквести від людей, яких я ніколи не зустрічав. Я й досі щоранку насамперед заглядаю в репозиторій, і досі в це не зовсім віриться.',
'system_notice.release_400.note_body_after': 'system_notice.release_notes.note_closing': 'Дякую, що ви тут. Ваш Maurice',
'4.0.0 коштував тижнів пізніх ночей — застосунок для телефона, конструктор книги, міграція сервера, і майже все це написано між північчю і другою. Це не скарга: мені подобається це робити. Просто чесна відповідь на те, як реліз такого розміру виходить із проєкту у вільний час.', 'system_notice.release_notes.support_lead':
'system_notice.release_400.note_closing': 'Дякую, що ви тут.', 'TREK безкоштовний і таким залишиться, а от сервери, домени й безліч пізніх ночей ні.',
'system_notice.release_400.note_signature': '— Maurice', 'system_notice.release_notes.support_text':
'system_notice.release_400.support_text': 'Якщо TREK заслужив місце у ваших подорожах, пригостіть мене кавою і допоможіть наблизити наступний реліз.',
'Підтримка — це те, на чому все тримається: сервери, домени і ті пізні ночі, з яких виходять такі релізи. Якщо TREK для вас чогось вартий, кава — найпряміший спосіб допомогти.', 'system_notice.release_notes.cta_bmc': 'Buy me a coffee',
'system_notice.release_400.cta_bmc': 'Buy me a coffee', 'system_notice.release_notes.cta_kofi': 'Підтримати на Ko-fi',
'system_notice.release_400.cta_kofi': 'Підтримати на Ko-fi',
}; };
export default system_notice; export default system_notice;
+36 -36
View File
@@ -55,41 +55,41 @@ const system_notice: TranslationStrings = {
'system_notice.pager.counter': '{current} / {total}', 'system_notice.pager.counter': '{current} / {total}',
'system_notice.pager.goto': 'Vào thông báo {n}', 'system_notice.pager.goto': 'Vào thông báo {n}',
'system_notice.pager.position': 'Thông báo {current} của {total}', 'system_notice.pager.position': 'Thông báo {current} của {total}',
// 4.0.0 release modal — the release on the left, the note from the maintainer on the right // The release modal. One stable set of keys: each big release swaps the copy in place.
'system_notice.release_400.eyebrow': 'Đã cập nhật', 'system_notice.release_notes.eyebrow': 'Đã cập nhật',
'system_notice.release_400.tag': 'Phiên bản', 'system_notice.release_notes.headline': 'Ba điều giờ đây TREK tự làm được.',
'system_notice.release_400.headline': 'Bản phát hành lớn nhất TREK từng có.', 'system_notice.release_notes.intro':
'system_notice.release_400.intro': 'API địa điểm của riêng mình, chuyến đi đường bộ được lên kế hoạch trọn vẹn từ đầu đến cuối, và lịch sử vị trí trở về trong tay bạn.',
'TREK có điện thoại, và một cuốn sách. Mười chín người đã viết nên bản này — cùng khoảng một trăm năm mươi lỗi được báo cáo.', 'system_notice.release_notes.features_label': 'Những điểm nhấn',
'system_notice.release_400.feature_mobile_title': 'TREK lên di động', 'system_notice.release_notes.features_aside': 'Chưa phải tất cả',
'system_notice.release_400.feature_mobile_body': 'system_notice.release_notes.feature_places_title': 'TREK Places API',
'Mọi thứ dưới 768px giờ là giao diện riêng — thanh dock kính, các bảng riêng, công cụ lập kế hoạch riêng. Mở TREK trên điện thoại.', 'system_notice.release_notes.feature_places_body':
'system_notice.release_400.feature_studio_title': 'TREK Studio', 'Công cụ lập kế hoạch du lịch mã nguồn mở đầu tiên tự vận hành API địa điểm của riêng mình. 73,6 triệu địa điểm, dựng lại mỗi tháng. Không cần khóa, không giới hạn lượt dùng.',
'system_notice.release_400.feature_studio_badge': 'Beta', 'system_notice.release_notes.feature_roadtrip_title': 'Tiện ích Chuyến đi đường bộ',
'system_notice.release_400.feature_studio_body': 'system_notice.release_notes.feature_roadtrip_body':
'Bản PDF của Journey đã thành một công cụ thiết kế sách ảnh. Nó tự dàn trang khi bạn yêu cầu, rồi lui ra một bên.', 'Chế độ chuyến đi đường bộ tự lên kế hoạch cho cả hành trình lái xe: tuyến đường, quãng đường, số giờ lái và các điểm dừng. Đây là một tiện ích bổ sung, được tắt cho đến khi quản trị viên bật lên.',
'system_notice.release_400.feature_vacay_title': 'Vacay học nốt', 'system_notice.release_notes.feature_dawarich_title': 'Tích hợp Dawarich',
'system_notice.release_400.feature_vacay_body': 'system_notice.release_notes.feature_dawarich_body':
'Nửa ngày, ngày bù và ngày linh hoạt, kỳ nghỉ học trên lưới — và một năm phép không nhất thiết bắt đầu từ tháng Một.', 'Lựa chọn tự lưu trữ thay cho Google Timeline, giờ đã đọc được ngay trong TREK. TREK chỉ đọc, và chỉ đọc mà thôi. Không có gì bị ghi ngược lại.',
'system_notice.release_400.feature_places_title': 'Địa điểm tự hiện ra, tệp dọn ra ngoài', 'system_notice.release_notes.footnote':
'system_notice.release_400.feature_places_body': 'Và còn cả một danh sách dài những thay đổi nhỏ hơn ở khắp phần còn lại của TREK.',
'Ảnh và mô tả tự điền vào trước khi bạn lưu một địa điểm. Và các tệp tải lên không còn phải nằm trên ổ đĩa chạy TREK nữa.', 'system_notice.release_notes.notes_label': 'Ghi chú phát hành',
'system_notice.release_400.footnote': 'system_notice.release_notes.note_eyebrow': 'Lời nhắn từ người bảo trì',
'Và đây mới là bốn trong số đó. 4.0.0 mang theo vài trăm thay đổi khác, từ Collections và Atlas cho tới toàn bộ máy chủ bên dưới.', 'system_notice.release_notes.note_title': 'Bạn là lý do tôi tiếp tục xây dựng TREK.',
'system_notice.release_400.note_eyebrow': 'Lời nhắn từ người bảo trì', 'system_notice.release_notes.note_body':
'system_notice.release_400.note_title': 'Cảm ơn bạn đã sử dụng TREK.', 'TREK bắt đầu là một công cụ nhỏ cho những chuyến đi của riêng tôi, viết sau giờ làm vì tôi muốn có một cách lên kế hoạch tốt hơn. Từ đó đến giờ nó chưa bao giờ thật sự ngừng lớn lên. Gần như mọi thứ bạn đang dùng đều được làm vào đêm khuya, vào cuối tuần, trên tàu, bên cạnh một công việc toàn thời gian, và đã có không ít buổi tối tôi lặng lẽ tự hỏi liệu có ai ngoài kia sẽ mở nó ra không.',
'system_notice.release_400.note_body': 'system_notice.release_notes.promise_label': 'Lời hứa',
'TREK bắt đầu như một công cụ nhỏ cho chuyến đi của riêng tôi, viết trong thời gian rảnh. Đến giờ vẫn vậy: buổi tối, cuối tuần, những giờ bên cạnh công việc toàn thời gian.\n\nĐã có lúc chỉ mình tôi. Giờ thì không nữa — mười chín người đã làm nên bản phát hành này, và hàng nghìn bạn đã đến với sao, báo lỗi, bản dịch và pull request. Tôi biết ơn tất cả.', 'system_notice.release_notes.promise_lead': 'TREK luôn miễn phí, mãi mãi.',
'system_notice.release_400.promise_label': 'Lời hứa', 'system_notice.release_notes.promise_text':
'system_notice.release_400.promise_text': 'Mọi tính năng, mọi bản cập nhật, cho tất cả mọi người. Không tầng trả phí, không đăng ký, không ràng buộc.',
'Phần mã nguồn mở của TREK vẫn miễn phí, mãi mãi. Không tầng trả phí, không đăng ký, không ràng buộc. Tôi hứa.', 'system_notice.release_notes.note_body_after':
'system_notice.release_400.note_body_after': 'Rồi các bạn đã mở nó. Chỉ trong vài tháng đã có hàng nghìn bạn: những ngôi sao, báo lỗi, bản dịch sang những ngôn ngữ tôi không biết nói, pull request từ những người tôi chưa từng gặp. Đến giờ, việc đầu tiên tôi làm mỗi sáng vẫn là mở kho mã, và cảm giác vẫn chưa hẳn là thật.',
'4.0.0 tốn nhiều tuần thức khuya — một ứng dụng điện thoại, một công cụ thiết kế sách, một lần chuyển máy chủ, phần lớn viết từ nửa đêm đến hai giờ. Không phải than phiền: tôi thích làm việc này. Đó chỉ là câu trả lời thật lòng cho việc một bản cỡ này ra đời từ một dự án lúc rảnh.', 'system_notice.release_notes.note_closing': 'Cảm ơn bạn đã ở đây. Thân mến, Maurice.',
'system_notice.release_400.note_closing': 'Cảm ơn bạn đã ở đây.', 'system_notice.release_notes.support_lead':
'system_notice.release_400.note_signature': '— Maurice', 'TREK miễn phí và sẽ luôn như vậy, nhưng máy chủ, tên miền và rất nhiều đêm thức khuya thì không.',
'system_notice.release_400.support_text': 'system_notice.release_notes.support_text':
'Sự ủng hộ là thứ giữ cho mọi thứ chạy — máy chủ, tên miền, và những đêm khuya biến thành các bản phát hành như thế này. Nếu TREK có giá trị với bạn, một ly cà phê là cách trực tiếp nhất để duy trì nó.', 'Nếu TREK đã có một chỗ trong những chuyến đi của bạn, hãy mời tôi một ly cà phê để bản phát hành tiếp theo tiếp tục ra đời.',
'system_notice.release_400.cta_bmc': 'Buy me a coffee', 'system_notice.release_notes.cta_bmc': 'Buy me a coffee',
'system_notice.release_400.cta_kofi': 'Hỗ trợ trên Ko-fi', 'system_notice.release_notes.cta_kofi': 'Hỗ trợ trên Ko-fi',
}; };
export default system_notice; export default system_notice;
+34 -35
View File
@@ -53,40 +53,39 @@ const system_notice: TranslationStrings = {
'system_notice.v3014_whitespace_collision.title': '需要操作:使用者帳戶衝突', 'system_notice.v3014_whitespace_collision.title': '需要操作:使用者帳戶衝突',
'system_notice.v3014_whitespace_collision.body': 'system_notice.v3014_whitespace_collision.body':
'3.0.14 版本升級偵測到一個或多個由儲存帳戶中前後空白字元引發的使用者名稱或電子郵件衝突。受影響的帳戶已自動重新命名。請檢查伺服器日誌中以 **[migration] WHITESPACE COLLISION** 開頭的行,以確認哪些帳戶需要審查。', '3.0.14 版本升級偵測到一個或多個由儲存帳戶中前後空白字元引發的使用者名稱或電子郵件衝突。受影響的帳戶已自動重新命名。請檢查伺服器日誌中以 **[migration] WHITESPACE COLLISION** 開頭的行,以確認哪些帳戶需要審查。',
// 4.0.0 release modal — the release on the left, the note from the maintainer on the right // The release modal. One stable set of keys: each big release swaps the copy in place.
'system_notice.release_400.eyebrow': '更新已安裝', 'system_notice.release_notes.eyebrow': '更新已安裝',
'system_notice.release_400.tag': '發布', 'system_notice.release_notes.headline': '三件事,TREK 現在自己就能做到。',
'system_notice.release_400.headline': 'TREK 有史以來最大的一次更新。', 'system_notice.release_notes.intro':
'system_notice.release_400.intro': '自行架設的地點 API,從出發到抵達全程規劃的公路旅行,還有重新回到你手中的位置紀錄。',
'TREK 有了手機端,也有了相簿書。這一版由十九個人寫成——隨之解決的還有大約一百五十個回報過的 bug。', 'system_notice.release_notes.features_label': '本次重頭戲',
'system_notice.release_400.feature_mobile_title': 'TREK 上手機', 'system_notice.release_notes.features_aside': '遠不止這些',
'system_notice.release_400.feature_mobile_body': 'system_notice.release_notes.feature_places_title': 'TREK Places API',
'768px 以下現在是一套獨立的介面——毛玻璃底欄、自己的彈出面板、自己的行程規劃器。用手機開啟 TREK 試試。', 'system_notice.release_notes.feature_places_body':
'system_notice.release_400.feature_studio_title': 'TREK Studio', '第一個自行架設地點 API 的開源旅遊規劃器。收錄 7360 萬個地點,每月重新建置。不需要金鑰,也沒有配額限制。',
'system_notice.release_400.feature_studio_badge': 'Beta', 'system_notice.release_notes.feature_roadtrip_title': '公路旅行擴充套件',
'system_notice.release_400.feature_studio_body': 'system_notice.release_notes.feature_roadtrip_body':
'Journey 的 PDF 變成了一個相簿書設計器。你讓它排版,它就把書排好,然後退到一邊。', '公路旅行模式會把整段車程規劃好:路線、里程、行車時數與停靠點。這是一個擴充套件,須由管理員啟用後才能使用。',
'system_notice.release_400.feature_vacay_title': 'Vacay 補齊了剩下的', 'system_notice.release_notes.feature_dawarich_title': 'Dawarich 整合',
'system_notice.release_400.feature_vacay_body': 'system_notice.release_notes.feature_dawarich_body':
'半天、補休與彈性假、日曆上的學校假期——還有不必從一月開始的休假年度。', 'Google Timeline 的自架替代方案,現在可以直接在 TREK 裡檢視。TREK 只讀取,也僅止於讀取,絕不會寫回任何資料。',
'system_notice.release_400.feature_places_title': '地點自己亮相,檔案搬出去', 'system_notice.release_notes.footnote': '除此之外,TREK 的其他部分還有一長串小改動。',
'system_notice.release_400.feature_places_body': 'system_notice.release_notes.notes_label': '版本說明',
'在你儲存一個地點之前,圖片和描述會自己填好。上傳的檔案也不必再放在 TREK 所在的磁碟上。', 'system_notice.release_notes.note_eyebrow': '來自維護者的話',
'system_notice.release_400.footnote': 'system_notice.release_notes.note_title': '是你們讓我一直堅持做 TREK。',
'這只是其中四項。4.0.0 還帶來數百項其他改動,從 Collections、Atlas 一直到底層的整個伺服器。', 'system_notice.release_notes.note_body':
'system_notice.release_400.note_eyebrow': '來自維護者的話', 'TREK 最初只是我為自己的旅行做的小工具,下班後一點一點寫出來,只因為我想更好地規劃旅行。後來它就再也沒有停止成長。你用到的幾乎每一項功能,都是在全職工作之外,在深夜、週末和火車上做出來的。也有很多個晚上,我會默默地想,這世界上究竟會不會有人打開它。',
'system_notice.release_400.note_title': '感謝你使用 TREK。', 'system_notice.release_notes.promise_label': '承諾',
'system_notice.release_400.note_body': 'system_notice.release_notes.promise_lead': 'TREK 永遠免費。',
'TREK 最初只是我為自己的旅行、用業餘時間做的一個小工具。現在依然如此:晚上、週末,全職工作之外的那些時間。\n\n有一陣子只有我一個人。現在不是了——十九個人一起做出了這一版,還有成千上萬的你們帶著星標、issue、翻譯和 pull request 來到這裡。這一切我都心懷感激。', 'system_notice.release_notes.promise_text':
'system_notice.release_400.promise_label': '承諾', '每一項功能、每一次更新,都屬於每一個人。沒有付費方案,沒有訂閱,沒有任何套路。',
'system_notice.release_400.promise_text': 'TREK 的開源部分永遠免費。沒有付費方案,沒有訂閱,沒有任何套路。我保證。', 'system_notice.release_notes.note_body_after':
'system_notice.release_400.note_body_after': '後來,你們真的來了。短短幾個月,就來了成千上萬的你們:有人按星標、回報 bug,有人把它翻譯成我不會說的語言,還有素未謀面的人送出 pull request。直到今天,我每天早上第一件事仍是打開儲存庫看看,而這一切還是有點不太真實。',
'4.0.0 花掉了好幾個星期的深夜——一個手機端、一個相簿書設計器、一次伺服器遷移,大多寫在午夜到兩點之間。這不是抱怨:我喜歡做這件事。只是想誠實地說明,這麼大的一個版本是怎麼從一個業餘專案裡出來的。', 'system_notice.release_notes.note_closing': '謝謝你來到這裡,Maurice 敬上。',
'system_notice.release_400.note_closing': '謝謝你來到這裡。', 'system_notice.release_notes.support_lead': 'TREK 現在免費,以後也永遠免費,但伺服器、網域和無數個深夜可不是免費的。',
'system_notice.release_400.note_signature': '— Maurice', 'system_notice.release_notes.support_text':
'system_notice.release_400.support_text': '如果它已經在你的旅行中佔有一席之地,請我喝杯咖啡,幫我把下一個版本繼續做出來吧。',
'是這些支持讓它繼續跑著——伺服器、網域,還有那些變成這樣一個版本的深夜。如果 TREK 對你有價值,請我喝杯咖啡是最直接的支持方式。', 'system_notice.release_notes.cta_bmc': 'Buy me a coffee',
'system_notice.release_400.cta_bmc': 'Buy me a coffee', 'system_notice.release_notes.cta_kofi': '在 Ko-fi 上支持我',
'system_notice.release_400.cta_kofi': '在 Ko-fi 上支持我',
}; };
export default system_notice; export default system_notice;
+32 -35
View File
@@ -52,40 +52,37 @@ const system_notice: TranslationStrings = {
'system_notice.v3014_whitespace_collision.title': '需要操作:用户账户冲突', 'system_notice.v3014_whitespace_collision.title': '需要操作:用户账户冲突',
'system_notice.v3014_whitespace_collision.body': 'system_notice.v3014_whitespace_collision.body':
'3.0.14 版本升级检测到一个或多个由存储账户中首尾空白字符引发的用户名或邮箱冲突。受影响的账户已自动重命名。请检查服务器日志中以 **[migration] WHITESPACE COLLISION** 开头的行,以确认哪些账户需要审查。', '3.0.14 版本升级检测到一个或多个由存储账户中首尾空白字符引发的用户名或邮箱冲突。受影响的账户已自动重命名。请检查服务器日志中以 **[migration] WHITESPACE COLLISION** 开头的行,以确认哪些账户需要审查。',
// 4.0.0 release modal — the release on the left, the note from the maintainer on the right // The release modal. One stable set of keys: each big release swaps the copy in place.
'system_notice.release_400.eyebrow': '更新已安装', 'system_notice.release_notes.eyebrow': '更新已安装',
'system_notice.release_400.tag': '发布', 'system_notice.release_notes.headline': '三件事,TREK 现在自己就能做到。',
'system_notice.release_400.headline': 'TREK 有史以来最大的一次更新。', 'system_notice.release_notes.intro': '自建的地点 API,从出发到抵达全程规划的公路旅行,还有重新回到你手中的位置历史。',
'system_notice.release_400.intro': 'system_notice.release_notes.features_label': '本次重头戏',
'TREK 有了手机端,也有了相册书。这一版由十九个人写成——随之解决的还有大约一百五十个报告过的 bug。', 'system_notice.release_notes.features_aside': '远不止这些',
'system_notice.release_400.feature_mobile_title': 'TREK 上手机', 'system_notice.release_notes.feature_places_title': 'TREK Places API',
'system_notice.release_400.feature_mobile_body': 'system_notice.release_notes.feature_places_body':
'768px 以下现在是一套独立的界面——毛玻璃底栏、自己的弹出面板、自己的行程规划器。用手机打开 TREK 试试。', '第一个自建地点 API 的开源旅行规划器。收录 7360 万个地点,每月重新构建。无需密钥,不限配额。',
'system_notice.release_400.feature_studio_title': 'TREK Studio', 'system_notice.release_notes.feature_roadtrip_title': '公路旅行扩展',
'system_notice.release_400.feature_studio_badge': 'Beta', 'system_notice.release_notes.feature_roadtrip_body':
'system_notice.release_400.feature_studio_body': '公路旅行模式会把整段车程规划好:路线、里程、驾驶时长和停靠点。这是一个扩展,需要管理员开启后才能使用。',
'Journey 的 PDF 变成了一个相册书设计器。你让它排版,它就把书排好,然后退到一边。', 'system_notice.release_notes.feature_dawarich_title': 'Dawarich 集成',
'system_notice.release_400.feature_vacay_title': 'Vacay 补齐了剩下的', 'system_notice.release_notes.feature_dawarich_body':
'system_notice.release_400.feature_vacay_body': 'Google Timeline 的自托管替代方案,现在可以直接在 TREK 里查看。TREK 只读取,仅此而已,绝不会回写任何数据。',
'半天、调休和弹性假、日历上的学校假期——还有不必从一月开始的假期年度。', 'system_notice.release_notes.footnote': '除此之外,TREK 的其他部分还有一长串小改动。',
'system_notice.release_400.feature_places_title': '地点自己亮相,文件搬出去', 'system_notice.release_notes.notes_label': '更新说明',
'system_notice.release_400.feature_places_body': 'system_notice.release_notes.note_eyebrow': '来自维护者的话',
'在你保存一个地点之前,图片和描述会自己填好。上传的文件也不必再放在 TREK 所在的磁盘上。', 'system_notice.release_notes.note_title': '是你们让我一直坚持做 TREK。',
'system_notice.release_400.footnote': 'system_notice.release_notes.note_body':
'这只是其中四项。4.0.0 还带来数百项其他改动,从 Collections、Atlas 一直到底层的整个服务端。', 'TREK 最初只是我为自己的旅行做的小工具,下班后一点点写出来,只因为我想更好地规划旅行。后来它就再没停止过成长。你用到的几乎每一样功能,都是在全职工作之外,在深夜、周末和火车上做出来的。也有很多个晚上,我会默默地想,这世上究竟会不会有人打开它。',
'system_notice.release_400.note_eyebrow': '来自维护者的话', 'system_notice.release_notes.promise_label': '承诺',
'system_notice.release_400.note_title': '感谢你使用 TREK。', 'system_notice.release_notes.promise_lead': 'TREK 永远免费。',
'system_notice.release_400.note_body': 'system_notice.release_notes.promise_text': '每个功能、每次更新,都属于每一个人。没有付费档位,没有订阅,没有套路。',
'TREK 最初只是我为自己的旅行、用业余时间做的一个小工具。现在依然如此:晚上、周末,全职工作之外的那些时间。\n\n有一阵子只有我一个人。现在不是了——十九个人一起做出了这一版,还有成千上万的你们带着星标、issue、翻译和 pull request 来到这里。这一切我都心怀感激。', 'system_notice.release_notes.note_body_after':
'system_notice.release_400.promise_label': '承诺', '后来,你们真的来了。短短几个月,就来了成千上万的你们:有人点星标、报 bug,有人把它翻译成我不会说的语言,还有素未谋面的人提交 pull request。直到今天,我每天早上第一件事仍是打开仓库看看,而这一切还是有点不像真的。',
'system_notice.release_400.promise_text': 'TREK 的开源部分永远免费。没有付费档位,没有订阅,没有套路。我保证。', 'system_notice.release_notes.note_closing': '谢谢你来到这里,Maurice 敬上。',
'system_notice.release_400.note_body_after': 'system_notice.release_notes.support_lead': 'TREK 现在免费,以后也永远免费,但服务器、域名和无数个深夜可不是免费的。',
'4.0.0 花掉了好几个星期的深夜——一个手机端、一个相册书设计器、一次服务端迁移,大多写在午夜到两点之间。这不是抱怨:我喜欢做这件事。只是想诚实地说明,这么大的一个版本是怎么从一个业余项目里出来的。', 'system_notice.release_notes.support_text':
'system_notice.release_400.note_closing': '谢谢你来到这里。', '如果它已经在你的旅行中占有一席之地,请我喝杯咖啡,帮我把下一个版本继续做出来吧。',
'system_notice.release_400.note_signature': '— Maurice', 'system_notice.release_notes.cta_bmc': 'Buy me a coffee',
'system_notice.release_400.support_text': 'system_notice.release_notes.cta_kofi': '在 Ko-fi 上支持',
'是这些支持让它继续跑着——服务器、域名,还有那些变成这样一个版本的深夜。如果 TREK 对你有价值,请我喝杯咖啡是最直接的支持方式。',
'system_notice.release_400.cta_bmc': 'Buy me a coffee',
'system_notice.release_400.cta_kofi': '在 Ko-fi 上支持',
}; };
export default system_notice; export default system_notice;
@@ -54,32 +54,33 @@ describe('systemNoticeDtoSchema', () => {
it('accepts a release notice and keeps its optional pieces optional', () => { it('accepts a release notice and keeps its optional pieces optional', () => {
const base = { const base = {
id: 'release-4-0-0', id: 'release-notes',
display: 'modal' as const, display: 'modal' as const,
severity: 'info' as const, severity: 'info' as const,
titleKey: 't', titleKey: 't',
bodyKey: 'b', bodyKey: 'b',
dismissible: true, dismissible: true,
release: { release: {
version: '4.0.0', version: '4.3.0',
eyebrowKey: 'e', eyebrowKey: 'e',
tagKey: 'tag',
headlineKey: 'h', headlineKey: 'h',
introKey: 'i', introKey: 'i',
featuresLabelKey: 'fl',
features: [ features: [
{ iconName: 'Smartphone', titleKey: 'f1t', bodyKey: 'f1b' }, { iconName: 'Database', titleKey: 'f1t', bodyKey: 'f1b' },
{ iconName: 'BookOpen', titleKey: 'f2t', bodyKey: 'f2b', badgeKey: 'beta' }, { iconName: 'Route', visual: 'roadtrip', titleKey: 'f2t', bodyKey: 'f2b' },
], ],
note: { note: {
eyebrowKey: 'ne', eyebrowKey: 'ne',
titleKey: 'nt', titleKey: 'nt',
bodyKey: 'nb', bodyKey: 'nb',
promiseLabelKey: 'pl', promiseLabelKey: 'pl',
promiseLeadKey: 'plead',
promiseTextKey: 'pt', promiseTextKey: 'pt',
bodyAfterKey: 'nba', bodyAfterKey: 'nba',
closingKey: 'nc', closingKey: 'nc',
signatureKey: 'ns',
}, },
supportLeadKey: 'slead',
supportTextKey: 's', supportTextKey: 's',
}, },
}; };
@@ -89,7 +90,7 @@ describe('systemNoticeDtoSchema', () => {
...base, ...base,
release: { release: {
...base.release, ...base.release,
stats: [{ value: '~150', labelKey: 'bugs' }], featuresAsideKey: 'fa',
notes: { labelKey: 'notes', href: 'https://example.test' }, notes: { labelKey: 'notes', href: 'https://example.test' },
footnoteKey: 'fn', footnoteKey: 'fn',
}, },
@@ -107,12 +108,13 @@ describe('systemNoticeDtoSchema', () => {
bodyKey: 'b', bodyKey: 'b',
dismissible: true, dismissible: true,
release: { release: {
version: '4.0.0', version: '4.3.0',
eyebrowKey: 'e', eyebrowKey: 'e',
tagKey: 'tag',
headlineKey: 'h', headlineKey: 'h',
introKey: 'i', introKey: 'i',
featuresLabelKey: 'fl',
features: [], features: [],
supportLeadKey: 'slead',
supportTextKey: 's', supportTextKey: 's',
}, },
}).success, }).success,
@@ -42,18 +42,15 @@ const noticeCtaSchema = z.discriminatedUnion('kind', [
}), }),
]); ]);
/** One "what changed" row in the release panel: icon, headline, prose, optional badge. */ /**
* One headline card in the release panel. `visual` names a small illustration the
* client draws for it; a name the client does not know falls back to the icon.
*/
const noticeReleaseFeatureSchema = z.object({ const noticeReleaseFeatureSchema = z.object({
iconName: z.string(), iconName: z.string(),
visual: z.string().optional(),
titleKey: z.string(), titleKey: z.string(),
bodyKey: z.string(), bodyKey: z.string(),
badgeKey: z.string().optional(),
});
/** A number worth stating next to the release — the figure itself is not translated. */
const noticeReleaseStatSchema = z.object({
value: z.string(),
labelKey: z.string(),
}); });
/** /**
@@ -63,28 +60,32 @@ const noticeReleaseStatSchema = z.object({
* shows lives here rather than inside the component. * shows lives here rather than inside the component.
*/ */
const noticeReleaseSchema = z.object({ const noticeReleaseSchema = z.object({
/** Shown as the display figure ("4.0.0") — a version string, not a semver gate. */ /** Shown as the display figure ("4.3.0"), a version string, not a semver gate. */
version: z.string(), version: z.string(),
eyebrowKey: z.string(), eyebrowKey: z.string(),
tagKey: z.string(),
headlineKey: z.string(), headlineKey: z.string(),
introKey: z.string(), introKey: z.string(),
featuresLabelKey: z.string(),
featuresAsideKey: z.string().optional(),
/** Two to four cards; the grid lays out any of those counts. */
features: z.array(noticeReleaseFeatureSchema), features: z.array(noticeReleaseFeatureSchema),
stats: z.array(noticeReleaseStatSchema).optional(),
notes: z.object({ labelKey: z.string(), href: z.string() }).optional(), notes: z.object({ labelKey: z.string(), href: z.string() }).optional(),
footnoteKey: z.string().optional(), footnoteKey: z.string().optional(),
note: z.object({ note: z.object({
eyebrowKey: z.string(), eyebrowKey: z.string(),
titleKey: z.string(), titleKey: z.string(),
/** Markdown paragraphs above the promise box. */ /** Paragraphs above the promise box, separated by a blank line. */
bodyKey: z.string(), bodyKey: z.string(),
promiseLabelKey: z.string(), promiseLabelKey: z.string(),
/** The promise's opening sentence, set in bold before the rest. */
promiseLeadKey: z.string(),
promiseTextKey: z.string(), promiseTextKey: z.string(),
/** Markdown paragraphs below the promise box. */ /** Paragraphs below the promise box, separated by a blank line. */
bodyAfterKey: z.string(), bodyAfterKey: z.string(),
closingKey: z.string(), closingKey: z.string(),
signatureKey: z.string(),
}), }),
/** The support footer's opening sentence, set in bold before the rest. */
supportLeadKey: z.string(),
supportTextKey: z.string(), supportTextKey: z.string(),
}); });