diff --git a/client/src/components/Admin/storage/AdminStoragePanel.test.tsx b/client/src/components/Admin/storage/AdminStoragePanel.test.tsx index 166bb45d6..823275608 100644 --- a/client/src/components/Admin/storage/AdminStoragePanel.test.tsx +++ b/client/src/components/Admin/storage/AdminStoragePanel.test.tsx @@ -982,11 +982,24 @@ describe('AdminStoragePanel', () => { ); expect(screen.getByText(/Moving Trip documents… 2\/5/)).toBeInTheDocument(); expect(screen.getByText(/Move finished: 4 copied, 0 skipped/)).toBeInTheDocument(); - expect(screen.getByText(/4 objects \(4\.0 KB\) remain on uploads-local — reclaim manually/)).toBeInTheDocument(); + expect(screen.getByText(/4 objects \(4\.0 KB\) remain on uploads-local, reclaim manually/)).toBeInTheDocument(); fireEvent.click(screen.getByRole('button', { name: 'Cancel move' })); await waitFor(() => expect(cancelledCategory).toBe('files')); }); + it('FE-ADMIN-STOR-050: the reclaimable line takes the plural form for the object count', async () => { + const state = baseState(); + (state as StorageAdminState).migrations = [ + { + category: 'journey', from: 'uploads-local', to: 'off-box', + status: 'done', done: 1, total: 1, copied: 1, skipped: 0, failed: 0, startedAt: 1, finishedAt: 2, + reclaimable: { objects: 1, bytes: 1024 }, + }, + ]; + await renderPanel(state); + expect(screen.getByText(/1 object \(1\.0 KB\) remains on uploads-local, reclaim manually/)).toBeInTheDocument(); + }); + it('FE-ADMIN-STOR-038: a done migration with sweep failures shows the doneFailures line; a clean one shows nothing extra', async () => { const state = baseState(); (state as StorageAdminState).migrations = [ diff --git a/client/src/components/Admin/storage/AdminStoragePanel.tsx b/client/src/components/Admin/storage/AdminStoragePanel.tsx index b613f1b66..acae89b84 100644 --- a/client/src/components/Admin/storage/AdminStoragePanel.tsx +++ b/client/src/components/Admin/storage/AdminStoragePanel.tsx @@ -716,7 +716,7 @@ export default function AdminStoragePanel(): React.ReactElement { {m.reclaimable && (

{t('storage.migrate.reclaimable', { - objects: String(m.reclaimable.objects), + count: m.reclaimable.objects, size: formatBytes(m.reclaimable.bytes), from: m.from, })} @@ -837,7 +837,7 @@ export default function AdminStoragePanel(): React.ReactElement { }) : t('storage.migrate.promptLine', { category: t(`storage.category.${c.category}`), - objects: String(c.objects), + count: c.objects, size: formatBytes(c.bytes ?? 0), from: c.from, to: c.to, diff --git a/client/src/components/Collab/useCollabChat.ts b/client/src/components/Collab/useCollabChat.ts index 51e071ae4..7660efdbd 100644 --- a/client/src/components/Collab/useCollabChat.ts +++ b/client/src/components/Collab/useCollabChat.ts @@ -124,7 +124,7 @@ export function useCollabChat(tripId: any, currentUser: any) { const addImageFiles = useCallback((incoming: File[] | FileList) => { images.add(incoming, ({ rejected, overflow }) => { if (rejected) toast.error(t('collab.chat.imageRejected')) - if (overflow) toast.error(t('collab.chat.imageLimit', { max: MAX_CHAT_IMAGES })) + if (overflow) toast.error(t('collab.chat.imageLimit', { count: MAX_CHAT_IMAGES })) }) }, [images, toast, t]) const removeImage = images.remove diff --git a/client/src/components/Dawarich/DawarichAcceptDialog.tsx b/client/src/components/Dawarich/DawarichAcceptDialog.tsx index f949e91b9..55706947a 100644 --- a/client/src/components/Dawarich/DawarichAcceptDialog.tsx +++ b/client/src/components/Dawarich/DawarichAcceptDialog.tsx @@ -147,7 +147,7 @@ export default function DawarichAcceptDialog({

- {t('dawarich.accept.duration', { minutes: suggestion.durationMinutes })} + {t('dawarich.accept.duration', { count: suggestion.durationMinutes })} {/* The source's own verdict, shown here rather than on every row of the list: since Dawarich 1.12.0 "unconfirmed" is the normal state @@ -180,7 +180,7 @@ export default function DawarichAcceptDialog({ {' — '} {t('dawarich.bucket.rule', { meters: DAWARICH_BUCKET_MATCH_RADIUS_M, - minutes: DAWARICH_BUCKET_MATCH_MIN_MINUTES, + count: DAWARICH_BUCKET_MATCH_MIN_MINUTES, })}

diff --git a/client/src/components/Dawarich/DawarichAtlasDialog.tsx b/client/src/components/Dawarich/DawarichAtlasDialog.tsx index afb5f0e88..c54aca4ec 100644 --- a/client/src/components/Dawarich/DawarichAtlasDialog.tsx +++ b/client/src/components/Dawarich/DawarichAtlasDialog.tsx @@ -216,7 +216,7 @@ export default function DawarichAtlasDialog({ scan?.truncated ? t('dawarich.bucket.truncated') : null, t('dawarich.bucket.rule', { meters: DAWARICH_BUCKET_MATCH_RADIUS_M, - minutes: DAWARICH_BUCKET_MATCH_MIN_MINUTES, + count: DAWARICH_BUCKET_MATCH_MIN_MINUTES, }), ]} > diff --git a/client/src/components/Roadtrip/RoadtripSidebarBadges.tsx b/client/src/components/Roadtrip/RoadtripSidebarBadges.tsx index b4610c8fe..3ed893449 100644 --- a/client/src/components/Roadtrip/RoadtripSidebarBadges.tsx +++ b/client/src/components/Roadtrip/RoadtripSidebarBadges.tsx @@ -208,7 +208,7 @@ export function Arrival({ entry }: { entry: ScheduleEntry }): React.ReactElement */ export function LateBadge({ late }: { late: ScheduleWarning }): React.ReactElement { const { t } = useTranslation() - const label = t(late.code === 'missedLeave' ? 'roadtrip.warn.missedLeave' : 'roadtrip.warn.late', { minutes: late.minutes ?? 0 }) + const label = t(late.code === 'missedLeave' ? 'roadtrip.warn.missedLeave' : 'roadtrip.warn.late', { count: late.minutes ?? 0 }) // The same two-part shell the stay and the drive findings wear, so a row of badges reads // as one set instead of a pill among boxes. return ( diff --git a/client/src/components/Roadtrip/RoadtripStayModal.tsx b/client/src/components/Roadtrip/RoadtripStayModal.tsx index 88457ff8b..b4c038c88 100644 --- a/client/src/components/Roadtrip/RoadtripStayModal.tsx +++ b/client/src/components/Roadtrip/RoadtripStayModal.tsx @@ -264,7 +264,7 @@ function LeaveTime({ stop, leave, until: leaveAt, is12h, onClose }: { {leave.missedBy !== null ? (

- {t('roadtrip.warn.missedLeave', { minutes: leave.missedBy })} + {t('roadtrip.warn.missedLeave', { count: leave.missedBy })}

) : (

diff --git a/client/src/components/Settings/ApiKeysSection.tsx b/client/src/components/Settings/ApiKeysSection.tsx index b65ef35a0..ca5a7ec1e 100644 --- a/client/src/components/Settings/ApiKeysSection.tsx +++ b/client/src/components/Settings/ApiKeysSection.tsx @@ -250,7 +250,7 @@ export default function ApiKeysSection(): React.ReactElement { {atLimit && (

-

{t('settings.apiKeys.limitReached', { max: MAX_KEYS })}

+

{t('settings.apiKeys.limitReached', { count: MAX_KEYS })}

)} diff --git a/client/src/components/Trips/TripFormModal.tsx b/client/src/components/Trips/TripFormModal.tsx index 0d6a07299..cc12fdb49 100644 --- a/client/src/components/Trips/TripFormModal.tsx +++ b/client/src/components/Trips/TripFormModal.tsx @@ -169,7 +169,7 @@ export default function TripFormModal({ isOpen, onClose, onSave, trip, onCoverUp // Only a range being set is held to the limit, as on the server: a trip that // already carries a longer one can still be renamed. const datesTouched = !trip || formData.start_date !== (trip.start_date || '') || formData.end_date !== (trip.end_date || '') - if (datesTouched && span > MAX_TRIP_DAYS) { setError(t('dashboard.tripTooLong', { days: MAX_TRIP_DAYS })); return } + if (datesTouched && span > MAX_TRIP_DAYS) { setError(t('dashboard.tripTooLong', { count: MAX_TRIP_DAYS })); return } } if (!formData.start_date && !formData.end_date) { const dc = Number(formData.day_count) diff --git a/client/src/mobile/screens/admin/MAdminStoragePanel.tsx b/client/src/mobile/screens/admin/MAdminStoragePanel.tsx index d662ba49f..9d82dfa59 100644 --- a/client/src/mobile/screens/admin/MAdminStoragePanel.tsx +++ b/client/src/mobile/screens/admin/MAdminStoragePanel.tsx @@ -703,7 +703,7 @@ export default function MAdminStoragePanel(): React.ReactElement { {m.reclaimable && (

{t('storage.migrate.reclaimable', { - objects: String(m.reclaimable.objects), + count: m.reclaimable.objects, size: formatBytes(m.reclaimable.bytes), from: m.from, })} @@ -834,7 +834,7 @@ export default function MAdminStoragePanel(): React.ReactElement { }) : t('storage.migrate.promptLine', { category: t(`storage.category.${c.category}`), - objects: String(c.objects), + count: c.objects, size: formatBytes(c.bytes ?? 0), from: c.from, to: c.to, diff --git a/client/src/mobile/screens/dashboard/MNewTripSheet.tsx b/client/src/mobile/screens/dashboard/MNewTripSheet.tsx index ea052d83b..38bece089 100644 --- a/client/src/mobile/screens/dashboard/MNewTripSheet.tsx +++ b/client/src/mobile/screens/dashboard/MNewTripSheet.tsx @@ -127,7 +127,7 @@ export default function MNewTripSheet({ open, trip, onClose, onSave, onCoverUpda const span = tripSpanDays(startDate, endDate) if (span < 1) { setError(t('dashboard.endDateError')); return null } const datesTouched = !trip || startDate !== (trip.start_date || '') || endDate !== (trip.end_date || '') - if (datesTouched && span > MAX_TRIP_DAYS) { setError(t('dashboard.tripTooLong', { days: MAX_TRIP_DAYS })); return null } + if (datesTouched && span > MAX_TRIP_DAYS) { setError(t('dashboard.tripTooLong', { count: MAX_TRIP_DAYS })); return null } } return { title: title.trim(), diff --git a/client/src/mobile/screens/trip/roadtrip/MRtStaySheet.tsx b/client/src/mobile/screens/trip/roadtrip/MRtStaySheet.tsx index 27915e81e..e8b18fcf0 100644 --- a/client/src/mobile/screens/trip/roadtrip/MRtStaySheet.tsx +++ b/client/src/mobile/screens/trip/roadtrip/MRtStaySheet.tsx @@ -345,7 +345,7 @@ function RtLeaveTime({ name, leave, arrival, departure, onClose }: { {leave.missedBy !== null ? (

) : (
diff --git a/client/src/mobile/screens/trip/roadtrip/MRtStopSheet.tsx b/client/src/mobile/screens/trip/roadtrip/MRtStopSheet.tsx index 1758f5295..5a6c02063 100644 --- a/client/src/mobile/screens/trip/roadtrip/MRtStopSheet.tsx +++ b/client/src/mobile/screens/trip/roadtrip/MRtStopSheet.tsx @@ -209,8 +209,8 @@ export default function MRtStopSheet({ planner, shell }: MTripSheetsProps) { ...day.driveWarnings.filter(w => w.index === index && (w.code === 'leg' || w.code === 'range')), ] const warningText = (w: ScheduleWarning): string => { - if (w.code === 'late') return t('roadtrip.warn.late', { minutes: w.minutes ?? 0 }) - if (w.code === 'missedLeave') return t('roadtrip.warn.missedLeave', { minutes: w.minutes ?? 0 }) + if (w.code === 'late') return t('roadtrip.warn.late', { count: w.minutes ?? 0 }) + if (w.code === 'missedLeave') return t('roadtrip.warn.missedLeave', { count: w.minutes ?? 0 }) if (w.code === 'range') return t('roadtrip.limit.range', { distance: formatDistance(w.sinceKm ?? 0, unit) }) return t('roadtrip.limit.legOver', { time: formatDurationShort((w.overMinutes ?? 0) * 60) }) } diff --git a/client/src/mobile/screens/trip/tabs/MCollabChat.tsx b/client/src/mobile/screens/trip/tabs/MCollabChat.tsx index bb43887ba..50147a5d1 100644 --- a/client/src/mobile/screens/trip/tabs/MCollabChat.tsx +++ b/client/src/mobile/screens/trip/tabs/MCollabChat.tsx @@ -162,7 +162,7 @@ export default function MCollabChat({ planner }: MCollabChatProps) { const addImageFiles = (incoming: FileList | File[]) => { images.add(incoming, ({ rejected, overflow }) => { if (rejected) toast.error(t('collab.chat.imageRejected')) - if (overflow) toast.error(t('collab.chat.imageLimit', { max: MAX_CHAT_IMAGES })) + if (overflow) toast.error(t('collab.chat.imageLimit', { count: MAX_CHAT_IMAGES })) }) } diff --git a/client/src/utils/dayAdd.ts b/client/src/utils/dayAdd.ts index 0c884d27e..343f26ac0 100644 --- a/client/src/utils/dayAdd.ts +++ b/client/src/utils/dayAdd.ts @@ -33,5 +33,5 @@ export function datedDayOption( ): Pick { const plan = trip ? planDatedAppend(trip, days.map(d => d.date)) : null if (!plan) return { nextDate: null, datedBlocked: null } - return { nextDate: plan.date, datedBlocked: plan.fits ? null : t('dashboard.tripTooLong', { days: MAX_TRIP_DAYS }) } + return { nextDate: plan.date, datedBlocked: plan.fits ? null : t('dashboard.tripTooLong', { count: MAX_TRIP_DAYS }) } } diff --git a/client/tests/unit/mobile/admin/MAdminStoragePanel.test.tsx b/client/tests/unit/mobile/admin/MAdminStoragePanel.test.tsx index 6da31e47e..3b5b8fa63 100644 --- a/client/tests/unit/mobile/admin/MAdminStoragePanel.test.tsx +++ b/client/tests/unit/mobile/admin/MAdminStoragePanel.test.tsx @@ -415,7 +415,7 @@ describe('MAdminStoragePanel', () => { ); expect(screen.getByText(/Moving Trip documents… 2\/5/)).toBeInTheDocument(); expect(screen.getByText(/Move finished: 4 copied, 0 skipped/)).toBeInTheDocument(); - expect(screen.getByText(/4 objects \(4\.0 KB\) remain on uploads-local — reclaim manually/)).toBeInTheDocument(); + expect(screen.getByText(/4 objects \(4\.0 KB\) remain on uploads-local, reclaim manually/)).toBeInTheDocument(); fireEvent.click(screen.getByRole('button', { name: 'Cancel move' })); await waitFor(() => expect(cancelledCategory).toBe('files')); }); diff --git a/shared/CLAUDE.md b/shared/CLAUDE.md index 656f760de..f8d70ab91 100644 --- a/shared/CLAUDE.md +++ b/shared/CLAUDE.md @@ -51,7 +51,7 @@ The parity rule governs **existing** routes; it is not a license to mint new deb - **`en/` is canonical.** Every other locale must have the identical file set and top-level keys — `i18n:parity:strict` enforces it in CI. When you add or rename a key, update every locale. - **Every locale gets a real translation; an English placeholder is not acceptable.** Write native phrasing with the locale's own punctuation and the same `{placeholders}` as `en`; if you genuinely cannot translate one, say so instead of filling it with English. Parity only checks that the key exists, so `i18n:parity:strict` also runs a ratchet (`scripts/i18n-untranslated.mjs`): per locale and file, the `// en-fallback` markers and the unmarked values identical to `en` may not grow past `scripts/i18n-untranslated-baseline.json`. An identical value is excused only when, after dropping placeholders, markup, URLs/e-mail/paths, the product names in `BRAND_NAMES` (Google Maps, Atlas, Immich) and the unit symbols in `UNITS`, no plain word is left (a word with a capital after its first letter, an acronym or a single letter does not count), so "{count} km", "GPX", "OAuth" and "Atlas" pass while "Settings" and "Source code" count. A single ordinary word that really is the locale's own (German "Status", French "Transport") carries `// same-as-en` on its declaration; the marker is honoured only on a value holding one plain word once the excused parts are dropped (on a phrase it is ignored, so it cannot wave a copied sentence through) and only in Latin-script locales (`LATIN_LOCALES`), because a Latin word in Japanese or Arabic is English whatever it says. A plural form en has no key for (Russian `.few`, Arabic `.two`) counts when it equals any form en spells out for that group. Every locale folder must be on `LATIN_LOCALES` or `NON_LATIN_LOCALES`, so a new language is classified there first. Deleting a marker without translating moves the string from one count to the other and still fails. After translating, run `npm run i18n:untranslated:update` to lower the baseline; nothing raises it. - **Count-bearing strings use plural forms, never `count === 1` in the caller.** The key holds the general form (the CLDR "other" category) and `key.zero|one|two|few|many` hold the forms the language's `Intl.PluralRules` selects for whole numbers (`plural.ts`); `t(key, { count })` (or `{ n }`) picks one. Pass the count as a number. Russian needs `.one`, `.few` and `.many`, Arabic all five, Japanese none. `i18n:parity` checks that every locale has exactly the forms its language reaches with whole numbers and none it never selects. A form may spell the number out (Arabic "ملف واحد") only where its category is that one number; French `one` also covers 0 and Russian `one` covers 21, so they keep `{count}`. A string whose wording changes with the number (the old "Copy to trip" for one place, "Copy {count} to trip" for more) is a plural group whose `one` drops the number where the language allows it, not two keys switched in the caller. -- **An `en` string carrying `{count}` or `{n}` must be a plural group**, even when the forms read the same (a label such as "Notes: {count}"), so every language can inflect. `i18n:parity` refuses one that is not, unless `NOT_PLURAL` in `scripts/i18n-parity.mjs` lists it with a reason: only for a number that is never a quantity (a day number, a step, a multiplier). An entry that stops matching fails too. +- **An `en` string carrying `{count}` or `{n}` must be a plural group**, even when the forms read the same (a label such as "Notes: {count}"), so every language can inflect. **A quantity is always named `{count}` (or `{n}`)**, the only params `t()` picks a form by: "All {days} days" read "Все 3 дней" in Russian. `i18n:parity` refuses an ungrouped string carrying `{count}`, `{n}` or one of the quantity names in `QUANTITY_PARAMS` (`{days}`, `{minutes}`, `{objects}`, `{max}` …), unless `NOT_PLURAL` in `scripts/i18n-parity.mjs` lists it with a reason: only for a number that is never a quantity (a day number, a step, a multiplier) or one followed by nothing but a unit symbol ("{minutes} min", "{max} MB"). A second number in the same string keeps its own name ("{over} of {count} days"). An entry that stops matching fails too. - **Further i18n specs run in `npm test`** and fail changes that parity lets through: placeholder parity (every `{placeholder}` in an `en` string must appear in each translation), no `en` string may call TREK "self-hosted" (the same build runs on managed installs; exemptions live in the spec), and a wording regression test for plugin permission descriptions (currently one string; add a case there when a permission's real behavior changes). None of these are part of `i18n:parity`, which checks key sets, plural forms, count strings and the untranslated ratchet. - **The i18n scripts read the tables as text** through `scripts/i18n-catalog.mjs`: a value must be one string literal on the key's line or the next, and anything else (a concatenation, a template literal) is an error rather than a skipped key. Their specs use the fixtures in `scripts/fixtures/`. That en holds every key the client names is checked on the client side (`npm run lint:i18n-keys` in `client/`). diff --git a/shared/scripts/fixtures/i18n/de/a.ts b/shared/scripts/fixtures/i18n/de/a.ts index 161ef0d78..ea0e1726c 100644 --- a/shared/scripts/fixtures/i18n/de/a.ts +++ b/shared/scripts/fixtures/i18n/de/a.ts @@ -10,5 +10,6 @@ const a = { 'a.quote': 'Es ist hier', 'a.multi': 'A long sentence that wraps onto the next line', + 'a.stay': '{days} Tage bleiben', }; export default a; diff --git a/shared/scripts/fixtures/i18n/en/a.ts b/shared/scripts/fixtures/i18n/en/a.ts index 83affa1e6..bc48e500b 100644 --- a/shared/scripts/fixtures/i18n/en/a.ts +++ b/shared/scripts/fixtures/i18n/en/a.ts @@ -10,5 +10,6 @@ const a = { 'a.quote': "It's here", 'a.multi': 'A long sentence that wraps onto the next line', + 'a.stay': 'Stay {days} days', }; export default a; diff --git a/shared/scripts/i18n-parity.mjs b/shared/scripts/i18n-parity.mjs index 33411f80e..64aefd1c9 100644 --- a/shared/scripts/i18n-parity.mjs +++ b/shared/scripts/i18n-parity.mjs @@ -21,8 +21,11 @@ // `Intl.PluralRules`, through the same helpers the client resolves with. // 4. Count strings: an en string carrying {count} or {n} (the two params // `t()` picks a plural form by) must be a plural group, so every -// language gets the forms it needs. The exceptions are NOT_PLURAL: a -// number that is never a quantity ("Day {n}", a step, a multiplier). +// language gets the forms it needs. So must one carrying a quantity +// under another name ({days}, {minutes}, {objects}, QUANTITY_PARAMS), +// which no form is picked by: it is renamed to {count}. The exceptions +// are NOT_PLURAL: a number that is never a quantity ("Day {n}", a step, +// a multiplier), or one followed only by a unit symbol. // 5. Untranslated strings: the marked `// en-fallback` and unmarked English // copies per locale and file may only shrink (i18n-untranslated.mjs, // which also lowers the baseline with --update). @@ -94,13 +97,37 @@ export const NOT_PLURAL = [ { key: 'system_notice.pager.goto', because: 'the position of a notice in the pager' }, { key: 'tours.addedToDay', because: 'the number of the day a tour was added to' }, { key: 'tours.planner.waypointLabel', because: 'the position of a waypoint on the tour' }, + { key: 'dawarich.duration.minutes', because: 'a duration in a unit symbol (min), the same for any number' }, + { key: 'dawarich.duration.hours', because: 'a duration in a unit symbol (h), the same for any number' }, + { key: 'dawarich.duration.hoursMinutes', because: 'a duration in unit symbols (h, min), the same for any number' }, + { key: 'files.uploadErrorSize', because: 'a size limit in a unit symbol (MB), the same for any number' }, ]; -const COUNT_PARAM_RE = /\{(?:count|n)\}/; +/** + * Param names that hold a quantity of something but are not the ones `t()` + * picks a plural form by. A string using one keeps a single form in every + * language ("Все {days} дней" for 2 days), so it is held like {count}: rename + * the param to {count} and make the string a plural group. + */ +export const QUANTITY_PARAMS = [ + 'days', + 'nights', + 'weeks', + 'months', + 'years', + 'hours', + 'minutes', + 'seconds', + 'items', + 'objects', + 'max', +]; + +const COUNT_PARAM_RE = new RegExp(`\\{(?:count|n|${QUANTITY_PARAMS.join('|')})\\}`); /** - * en strings carrying a count param outside any plural group, and NOT_PLURAL - * entries that no longer name such a string. + * en strings carrying a count or quantity param outside any plural group, + * and NOT_PLURAL entries that no longer name such a string. */ function checkCountStrings(enFiles, notPlural = NOT_PLURAL, root = I18N_ROOT) { const allowed = new Set(notPlural.map((e) => e.key)); @@ -233,9 +260,11 @@ function formatReport(report) { if (ungrouped.length === 0 && stale.length === 0) { lines.push('Count strings: OK'); } else { - lines.push('Count strings: en strings with {count} or {n} that are no plural group'); + lines.push('Count strings: en strings with {count}, {n} or a quantity param that are no plural group'); for (const { file, key } of ungrouped) { - lines.push(` en/${file}: ${key} (add ${key}.one and the other forms, see shared/CLAUDE.md)`); + lines.push( + ` en/${file}: ${key} (name the quantity {count} and add ${key}.one and the other forms, see shared/CLAUDE.md)`, + ); } for (const key of stale) lines.push(` NOT_PLURAL lists ${key}, which is no ungrouped count string: remove it`); } diff --git a/shared/src/i18n/ar/collab.ts b/shared/src/i18n/ar/collab.ts index 74958147d..d1ae3dbc3 100644 --- a/shared/src/i18n/ar/collab.ts +++ b/shared/src/i18n/ar/collab.ts @@ -116,7 +116,12 @@ const collab: TranslationStrings = { 'collab.polls.delete': 'حذف', 'collab.polls.closedSection': 'مغلق', 'collab.notes.websitePlaceholder': 'https://...', // en-fallback - 'collab.chat.imageLimit': 'يمكنك إرفاق ما يصل إلى {max} صور لكل رسالة', + 'collab.chat.imageLimit': 'يمكنك إرفاق ما يصل إلى {count} صورة لكل رسالة', + 'collab.chat.imageLimit.zero': 'يمكنك إرفاق ما يصل إلى {count} صورة لكل رسالة', + 'collab.chat.imageLimit.one': 'يمكنك إرفاق صورة واحدة فقط لكل رسالة', + 'collab.chat.imageLimit.two': 'يمكنك إرفاق صورتين كحد أقصى لكل رسالة', + 'collab.chat.imageLimit.few': 'يمكنك إرفاق ما يصل إلى {count} صور لكل رسالة', + 'collab.chat.imageLimit.many': 'يمكنك إرفاق ما يصل إلى {count} صورة لكل رسالة', 'collab.chat.uploading': 'جارٍ الرفع {percent}%', 'collab.chat.attachImages': 'إرفاق صور', 'collab.chat.attachedImage': 'صورة مرفقة', diff --git a/shared/src/i18n/ar/dashboard.ts b/shared/src/i18n/ar/dashboard.ts index d7eedef6f..05dd4bfa7 100644 --- a/shared/src/i18n/ar/dashboard.ts +++ b/shared/src/i18n/ar/dashboard.ts @@ -127,7 +127,12 @@ const dashboard: TranslationStrings = { 'dashboard.useUnsplashPhoto': 'استخدم صورة من Unsplash بواسطة {photographer}', 'dashboard.titleRequired': 'العنوان مطلوب', 'dashboard.endDateError': 'يجب أن يكون تاريخ النهاية بعد البداية', - 'dashboard.tripTooLong': 'لا يمكن أن تتجاوز مدة الرحلة {days} يومًا', + 'dashboard.tripTooLong': 'لا يمكن أن تتجاوز مدة الرحلة {count} يوم', + 'dashboard.tripTooLong.zero': 'لا يمكن أن تتجاوز مدة الرحلة {count} يوم', + 'dashboard.tripTooLong.one': 'لا يمكن أن تتجاوز مدة الرحلة يومًا واحدًا', + 'dashboard.tripTooLong.two': 'لا يمكن أن تتجاوز مدة الرحلة يومين', + 'dashboard.tripTooLong.few': 'لا يمكن أن تتجاوز مدة الرحلة {count} أيام', + 'dashboard.tripTooLong.many': 'لا يمكن أن تتجاوز مدة الرحلة {count} يومًا', 'dashboard.dateShiftTitle': 'تاريخ بداية جديد', 'dashboard.dateShiftIntro': 'لقد غيّرت موعد بداية هذه الرحلة. كيف تريد أن تتبع خططك التواريخ الجديدة؟', 'dashboard.dateShiftKeepBookings': 'إبقاء الحجوزات في تواريخها', diff --git a/shared/src/i18n/ar/dawarich.ts b/shared/src/i18n/ar/dawarich.ts index 7324b8c50..8c7b51ab5 100644 --- a/shared/src/i18n/ar/dawarich.ts +++ b/shared/src/i18n/ar/dawarich.ts @@ -132,7 +132,12 @@ const dawarich: TranslationStrings = { 'dawarich.accept.confirm.journal': 'إضافة المدوّنة', 'dawarich.accept.confirm.bucket_list': 'اشطبها', 'dawarich.accept.recorded': 'مسجَّلة من {from} حتى {to}', - 'dawarich.accept.duration': '{minutes} دقيقة', + 'dawarich.accept.duration': '{count} دقيقة', + 'dawarich.accept.duration.zero': '{count} دقيقة', + 'dawarich.accept.duration.one': 'دقيقة واحدة', + 'dawarich.accept.duration.two': 'دقيقتان', + 'dawarich.accept.duration.few': '{count} دقائق', + 'dawarich.accept.duration.many': '{count} دقيقة', 'dawarich.accept.name': 'الاسم', 'dawarich.accept.date': 'التاريخ', 'dawarich.accept.from': 'الوصول', @@ -225,7 +230,12 @@ const dawarich: TranslationStrings = { 'dawarich.again': 'تحقق مرة أخرى', 'dawarich.bucket.metersAway': 'على بُعد {meters} م', 'dawarich.bucket.kilometersAway': 'على بُعد {km} كم', - 'dawarich.bucket.rule': 'تُحتسب الأمنية محققة ضمن {meters} م وبعد {minutes} دقيقة في المكان.', + 'dawarich.bucket.rule': 'تُحتسب الأمنية محققة ضمن {meters} م وبعد {count} دقيقة في المكان.', + 'dawarich.bucket.rule.zero': 'تُحتسب الأمنية محققة ضمن {meters} م وبعد {count} دقيقة في المكان.', + 'dawarich.bucket.rule.one': 'تُحتسب الأمنية محققة ضمن {meters} م وبعد دقيقة واحدة في المكان.', + 'dawarich.bucket.rule.two': 'تُحتسب الأمنية محققة ضمن {meters} م وبعد دقيقتين في المكان.', + 'dawarich.bucket.rule.few': 'تُحتسب الأمنية محققة ضمن {meters} م وبعد {count} دقائق في المكان.', + 'dawarich.bucket.rule.many': 'تُحتسب الأمنية محققة ضمن {meters} م وبعد {count} دقيقة في المكان.', 'dawarich.journey.dayStays.other': '{count} إقامة من Dawarich', 'dawarich.journey.dayStays.zero': 'لا توجد إقامات من Dawarich', 'dawarich.journey.dayStays.one': 'إقامة واحدة من Dawarich', diff --git a/shared/src/i18n/ar/roadtrip.ts b/shared/src/i18n/ar/roadtrip.ts index 01da48bd8..82e18103b 100644 --- a/shared/src/i18n/ar/roadtrip.ts +++ b/shared/src/i18n/ar/roadtrip.ts @@ -54,7 +54,12 @@ const roadtrip: TranslationStrings = { 'roadtrip.window.incomplete': 'يلزم توفر جميع المسارات الرابطة لحساب الاستراحات اليومية.', 'roadtrip.window.conflict': 'يتعارض وقت ثابت مع القيادة والاستراحات. تبقى الأوقات اليدوية كما هي؛ تم إيقاف التخطيط التلقائي مؤقتًا.', - 'roadtrip.window.tooLong': 'تتطلب هذه الأوقات أكثر من {days} يومًا إضافيًا. اختر فترة يومية أطول.', + 'roadtrip.window.tooLong': 'تتطلب هذه الأوقات أكثر من {count} يوم إضافي. اختر فترة يومية أطول.', + 'roadtrip.window.tooLong.zero': 'تتطلب هذه الأوقات أكثر من {count} يوم إضافي. اختر فترة يومية أطول.', + 'roadtrip.window.tooLong.one': 'تتطلب هذه الأوقات أكثر من يوم إضافي واحد. اختر فترة يومية أطول.', + 'roadtrip.window.tooLong.two': 'تتطلب هذه الأوقات أكثر من يومين إضافيين. اختر فترة يومية أطول.', + 'roadtrip.window.tooLong.few': 'تتطلب هذه الأوقات أكثر من {count} أيام إضافية. اختر فترة يومية أطول.', + 'roadtrip.window.tooLong.many': 'تتطلب هذه الأوقات أكثر من {count} يومًا إضافيًا. اختر فترة يومية أطول.', 'roadtrip.mode.roadtrip': 'رحلة برية', 'roadtrip.mode.days': 'الأيام', 'roadtrip.mode.label': 'عرض الخطة', @@ -105,8 +110,18 @@ const roadtrip: TranslationStrings = { 'roadtrip.limit.minutes': 'دقيقة', 'roadtrip.limit.off': 'معطل', 'roadtrip.limit.blockNote': 'كتلة واحدة = {distance}', - 'roadtrip.limit.echoOver': '{over} من {days} أيام تتجاوز حدّك.', - 'roadtrip.limit.echoNone': 'كل الأيام {days} ضمن حدودك.', + 'roadtrip.limit.echoOver': '{over} من {count} يوم تتجاوز حدّك.', + 'roadtrip.limit.echoOver.zero': '{over} من {count} يوم تتجاوز حدّك.', + 'roadtrip.limit.echoOver.one': '{over} من يوم واحد يتجاوز حدّك.', + 'roadtrip.limit.echoOver.two': '{over} من يومين تتجاوز حدّك.', + 'roadtrip.limit.echoOver.few': '{over} من {count} أيام تتجاوز حدّك.', + 'roadtrip.limit.echoOver.many': '{over} من {count} يومًا تتجاوز حدّك.', + 'roadtrip.limit.echoNone': 'كل الأيام {count} ضمن حدودك.', + 'roadtrip.limit.echoNone.zero': 'كل الأيام {count} ضمن حدودك.', + 'roadtrip.limit.echoNone.one': 'اليوم الوحيد ضمن حدودك.', + 'roadtrip.limit.echoNone.two': 'اليومان كلاهما ضمن حدودك.', + 'roadtrip.limit.echoNone.few': 'كل الأيام {count} ضمن حدودك.', + 'roadtrip.limit.echoNone.many': 'كل الأيام {count} ضمن حدودك.', 'roadtrip.limit.echoDry': '{count} مقطع بلا محطة يمكن بلوغها.', 'roadtrip.limit.echoDry.zero': 'لا توجد مقاطع بلا محطة يمكن بلوغها.', 'roadtrip.limit.echoDry.one': 'مقطع واحد بلا محطة يمكن بلوغها.', @@ -308,8 +323,18 @@ const roadtrip: TranslationStrings = { 'roadtrip.stop.computed': 'محسوب من زمن القيادة', 'roadtrip.stop.endIsLeave': 'في الرحلة البرية، تنطلق الرحلة في هذا الوقت.', 'roadtrip.via.hint': 'اسحب لإعادة تشكيل المسار، وانقر بالزر الأيمن للإزالة', - 'roadtrip.warn.late': 'الوصول بعد {minutes} دقيقة من الوقت المحدد', - 'roadtrip.warn.missedLeave': 'الوصول بعد {minutes} دقيقة من وقت المغادرة المحدد', + 'roadtrip.warn.late': 'الوصول بعد {count} دقيقة من الوقت المحدد', + 'roadtrip.warn.late.zero': 'الوصول بعد {count} دقيقة من الوقت المحدد', + 'roadtrip.warn.late.one': 'الوصول بعد دقيقة واحدة من الوقت المحدد', + 'roadtrip.warn.late.two': 'الوصول بعد دقيقتين من الوقت المحدد', + 'roadtrip.warn.late.few': 'الوصول بعد {count} دقائق من الوقت المحدد', + 'roadtrip.warn.late.many': 'الوصول بعد {count} دقيقة من الوقت المحدد', + 'roadtrip.warn.missedLeave': 'الوصول بعد {count} دقيقة من وقت المغادرة المحدد', + 'roadtrip.warn.missedLeave.zero': 'الوصول بعد {count} دقيقة من وقت المغادرة المحدد', + 'roadtrip.warn.missedLeave.one': 'الوصول بعد دقيقة واحدة من وقت المغادرة المحدد', + 'roadtrip.warn.missedLeave.two': 'الوصول بعد دقيقتين من وقت المغادرة المحدد', + 'roadtrip.warn.missedLeave.few': 'الوصول بعد {count} دقائق من وقت المغادرة المحدد', + 'roadtrip.warn.missedLeave.many': 'الوصول بعد {count} دقيقة من وقت المغادرة المحدد', 'roadtrip.warn.overnight': 'اليوم التالي', 'roadtrip.spill.title': 'من اليوم {number}', 'roadtrip.spill.departs': 'المغادرة {time}', diff --git a/shared/src/i18n/ar/settings.ts b/shared/src/i18n/ar/settings.ts index 614d19387..1aea8f4f2 100644 --- a/shared/src/i18n/ar/settings.ts +++ b/shared/src/i18n/ar/settings.ts @@ -640,7 +640,18 @@ const settings: TranslationStrings = { 'settings.apiKeys.endpoint': 'نقطة النهاية', 'settings.apiKeys.neverUsed': 'لم يُستخدم قط', 'settings.apiKeys.loadFailed': 'تعذّر تحميل مفاتيحك. أعد تحميل الصفحة للمحاولة مرة أخرى.', - 'settings.apiKeys.limitReached': 'لديك {max} مفاتيح، وهو الحد الأقصى للحساب الواحد. احذف مفتاحًا لم تعد تستخدمه لإنشاء مفتاح جديد.', + 'settings.apiKeys.limitReached': + 'لديك {count} مفتاح، وهو الحد الأقصى للحساب الواحد. احذف مفتاحًا لم تعد تستخدمه لإنشاء مفتاح جديد.', + 'settings.apiKeys.limitReached.zero': + 'لديك {count} مفتاح، وهو الحد الأقصى للحساب الواحد. احذف مفتاحًا لم تعد تستخدمه لإنشاء مفتاح جديد.', + 'settings.apiKeys.limitReached.one': + 'لديك مفتاح واحد، وهو الحد الأقصى للحساب الواحد. احذفه إن لم تعد تستخدمه لإنشاء مفتاح جديد.', + 'settings.apiKeys.limitReached.two': + 'لديك مفتاحان، وهو الحد الأقصى للحساب الواحد. احذف مفتاحًا لم تعد تستخدمه لإنشاء مفتاح جديد.', + 'settings.apiKeys.limitReached.few': + 'لديك {count} مفاتيح، وهو الحد الأقصى للحساب الواحد. احذف مفتاحًا لم تعد تستخدمه لإنشاء مفتاح جديد.', + 'settings.apiKeys.limitReached.many': + 'لديك {count} مفتاحًا، وهو الحد الأقصى للحساب الواحد. احذف مفتاحًا لم تعد تستخدمه لإنشاء مفتاح جديد.', 'settings.apiKeys.copyFailed': 'تعذّر النسخ. حدّد النص وانسخه يدويًا.', 'settings.apiKeys.modal.createTitle': 'إنشاء مفتاح API', 'settings.apiKeys.modal.name': 'الاسم', diff --git a/shared/src/i18n/ar/storage.ts b/shared/src/i18n/ar/storage.ts index 523925570..f87417d5e 100644 --- a/shared/src/i18n/ar/storage.ts +++ b/shared/src/i18n/ar/storage.ts @@ -124,7 +124,12 @@ const storage: TranslationStrings = { // Category migration (copy → flip → delta sweep) 'storage.migrate.promptTitle': 'هل تريد نقل الكائنات الحالية إلى الواجهة الخلفية الجديدة؟', - 'storage.migrate.promptLine': '{category}: {objects} كائن ({size}) من {from} إلى {to}', + 'storage.migrate.promptLine': '{category}: {count} كائن ({size}) من {from} إلى {to}', + 'storage.migrate.promptLine.zero': '{category}: {count} كائن ({size}) من {from} إلى {to}', + 'storage.migrate.promptLine.one': '{category}: كائن واحد ({size}) من {from} إلى {to}', + 'storage.migrate.promptLine.two': '{category}: كائنان ({size}) من {from} إلى {to}', + 'storage.migrate.promptLine.few': '{category}: {count} كائنات ({size}) من {from} إلى {to}', + 'storage.migrate.promptLine.many': '{category}: {count} كائنًا ({size}) من {from} إلى {to}', 'storage.migrate.promptLineUnknown': '{category}: حجم غير معروف (لم يُجرَ فحص استخدام بعد) من {from} إلى {to}', 'storage.migrate.move': 'نقل الكائنات الحالية', 'storage.migrate.routeOnly': 'توجيه الكتابات الجديدة فقط', @@ -133,7 +138,12 @@ const storage: TranslationStrings = { 'storage.migrate.doneFailures': '{failed} فشل — لم يتم نسخ تلك الكائنات إلى الواجهة الخلفية الجديدة', 'storage.migrate.failed': 'فشل النقل: {error} — لم يتم تبديل الفئة', 'storage.migrate.cancelled': 'تم إلغاء النقل — لم يتم تبديل أي شيء', - 'storage.migrate.reclaimable': '{objects} كائن ({size}) لا تزال على {from} — استرجعها يدويًا', + 'storage.migrate.reclaimable': '{count} كائن ({size}) لا تزال على {from}، استرجعها يدويًا', + 'storage.migrate.reclaimable.zero': '{count} كائن ({size}) لا تزال على {from}، استرجعها يدويًا', + 'storage.migrate.reclaimable.one': 'كائن واحد ({size}) لا يزال على {from}، استرجعه يدويًا', + 'storage.migrate.reclaimable.two': 'كائنان ({size}) لا يزالان على {from}، استرجعهما يدويًا', + 'storage.migrate.reclaimable.few': '{count} كائنات ({size}) لا تزال على {from}، استرجعها يدويًا', + 'storage.migrate.reclaimable.many': '{count} كائنًا ({size}) لا تزال على {from}، استرجعها يدويًا', 'storage.migrate.cancel': 'إلغاء النقل', 'storage.migrate.promptCancel': 'إلغاء', 'storage.migrate.queued': 'في قائمة الانتظار: {categories}', diff --git a/shared/src/i18n/az/collab.ts b/shared/src/i18n/az/collab.ts index 37c55147c..4ad2c2b66 100644 --- a/shared/src/i18n/az/collab.ts +++ b/shared/src/i18n/az/collab.ts @@ -112,8 +112,8 @@ const collab: TranslationStrings = { 'collab.polls.delete': 'Sil', 'collab.polls.closedSection': 'Bağlanmış sorğular', - 'collab.chat.imageLimit': - 'Hər mesaja maksimum {max} şəkil əlavə edə bilərsiniz', + 'collab.chat.imageLimit': 'Hər mesaja maksimum {count} şəkil əlavə edə bilərsiniz', + 'collab.chat.imageLimit.one': 'Hər mesaja yalnız {count} şəkil əlavə edə bilərsiniz', 'collab.chat.uploading': 'Yüklənir: {percent}%', 'collab.chat.attachImages': 'Şəkillər əlavə et', 'collab.chat.attachedImage': 'Əlavə edilmiş şəkil', diff --git a/shared/src/i18n/az/dashboard.ts b/shared/src/i18n/az/dashboard.ts index 4d676f3b2..cdfceb5a6 100644 --- a/shared/src/i18n/az/dashboard.ts +++ b/shared/src/i18n/az/dashboard.ts @@ -113,7 +113,8 @@ const dashboard: TranslationStrings = { 'dashboard.useUnsplashPhoto': '{photographer} tərəfindən çəkilmiş Unsplash şəklindən istifadə et', 'dashboard.titleRequired': 'Başlıq tələb olunur', 'dashboard.endDateError': 'Bitmə tarixi başlama tarixindən sonra olmalıdır', - 'dashboard.tripTooLong': 'Səyahət ən çox {days} gün davam edə bilər', + 'dashboard.tripTooLong': 'Səyahət ən çox {count} gün davam edə bilər', + 'dashboard.tripTooLong.one': 'Səyahət ən çox {count} gün davam edə bilər', 'dashboard.dateShiftTitle': 'Yeni başlama tarixi', 'dashboard.dateShiftIntro': 'Səyahətin başlama tarixini dəyişdiniz. Planlarınız yeni tarixlərə necə uyğunlaşdırılsın?', 'dashboard.dateShiftKeepBookings': 'Rezervasiyaların tarixlərini saxla', diff --git a/shared/src/i18n/az/dawarich.ts b/shared/src/i18n/az/dawarich.ts index 2574ce164..3cfd43c13 100644 --- a/shared/src/i18n/az/dawarich.ts +++ b/shared/src/i18n/az/dawarich.ts @@ -116,7 +116,8 @@ const dawarich: TranslationStrings = { 'dawarich.accept.confirm.journal': 'Qeyd əlavə et', 'dawarich.accept.confirm.bucket_list': 'Tamamlandı kimi işarələ', 'dawarich.accept.recorded': '{from}–{to} aralığında qeydə alınıb', - 'dawarich.accept.duration': '{minutes} dəq.', + 'dawarich.accept.duration': '{count} dəq.', + 'dawarich.accept.duration.one': '{count} dəq.', 'dawarich.accept.name': 'Ad', 'dawarich.accept.date': 'Tarix', 'dawarich.accept.from': 'Çatma', @@ -181,7 +182,10 @@ const dawarich: TranslationStrings = { 'dawarich.again': 'Yenidən yoxla', 'dawarich.bucket.metersAway': '{meters} m uzaqda', 'dawarich.bucket.kilometersAway': '{km} km uzaqda', - 'dawarich.bucket.rule': 'Arzu məkandan {meters} m məsafə daxilində və orada ən azı {minutes} dəqiqə qaldıqda tamamlanmış sayılır.', + 'dawarich.bucket.rule': + 'Arzu məkandan {meters} m məsafə daxilində və orada ən azı {count} dəqiqə qaldıqda tamamlanmış sayılır.', + 'dawarich.bucket.rule.one': + 'Arzu məkandan {meters} m məsafə daxilində və orada ən azı {count} dəqiqə qaldıqda tamamlanmış sayılır.', 'dawarich.journey.dayStays.one': 'Dawarich-dən 1 dayanma qeydi', 'dawarich.journey.dayStays.other': 'Dawarich-dən {count} dayanma qeydi', diff --git a/shared/src/i18n/az/roadtrip.ts b/shared/src/i18n/az/roadtrip.ts index 0236c55ff..b3a6357ec 100644 --- a/shared/src/i18n/az/roadtrip.ts +++ b/shared/src/i18n/az/roadtrip.ts @@ -54,7 +54,9 @@ const roadtrip: TranslationStrings = { 'roadtrip.window.conflict': 'Sabit vaxt yol və günlük fasilələrlə ziddiyyət təşkil edir. Əl ilə təyin edilmiş vaxtlar dəyişdirilmir; avtomatik planlaşdırma dayandırılıb.', 'roadtrip.window.tooLong': - 'Bu səyahət vaxtları {days} ədəddən çox əlavə gün tələb edəcək. Daha uzun günlük vaxt aralığı seçin.', + 'Bu səyahət vaxtları {count} gündən çox əlavə vaxt tələb edəcək. Daha uzun günlük vaxt aralığı seçin.', + 'roadtrip.window.tooLong.one': + 'Bu səyahət vaxtları {count} gündən çox əlavə vaxt tələb edəcək. Daha uzun günlük vaxt aralığı seçin.', 'roadtrip.mode.roadtrip': 'Avtomobil səyahəti', 'roadtrip.mode.days': 'Günlər', 'roadtrip.mode.label': 'Plan görünüşü', @@ -101,8 +103,10 @@ const roadtrip: TranslationStrings = { 'roadtrip.limit.minutes': 'dəq.', 'roadtrip.limit.off': 'deaktiv', 'roadtrip.limit.blockNote': 'Bir blok = {distance}', - 'roadtrip.limit.echoOver': '{days} gündən {over} günü limitinizi keçir.', - 'roadtrip.limit.echoNone': 'Bütün {days} gün limitləriniz daxilindədir.', + 'roadtrip.limit.echoOver': '{count} gündən {over} günü limitinizi keçir.', + 'roadtrip.limit.echoOver.one': '{count} gündən {over} günü limitinizi keçir.', + 'roadtrip.limit.echoNone': 'Bütün {count} gün limitləriniz daxilindədir.', + 'roadtrip.limit.echoNone.one': 'Yeganə gün limitləriniz daxilindədir.', 'roadtrip.limit.echoDry': 'Çatmaq mümkün olan dayanacağı olmayan {count} marşrut hissəsi.', 'roadtrip.limit.echoDry.one': 'Çatmaq mümkün olan dayanacağı olmayan {count} marşrut hissəsi.', 'roadtrip.limit.echoEmpty': 'Bu tənzimləmələrin təsirini görmək üçün avtomobil səyahəti açın.', @@ -268,8 +272,10 @@ const roadtrip: TranslationStrings = { 'roadtrip.stop.computed': 'Yoldan hesablanıb', 'roadtrip.stop.endIsLeave': 'Avtomobil səyahətində yol bu vaxtda davam edir.', 'roadtrip.via.hint': 'Marşrutu dəyişmək üçün sürükləyin, silmək üçün sağ klikləyin', - 'roadtrip.warn.late': 'Təyin etdiyiniz vaxtdan {minutes} dəq. sonra çatır', - 'roadtrip.warn.missedLeave': 'Təyin etdiyiniz çıxış vaxtından {minutes} dəq. sonra çatır', + 'roadtrip.warn.late': 'Təyin etdiyiniz vaxtdan {count} dəq. sonra çatır', + 'roadtrip.warn.late.one': 'Təyin etdiyiniz vaxtdan {count} dəq. sonra çatır', + 'roadtrip.warn.missedLeave': 'Təyin etdiyiniz çıxış vaxtından {count} dəq. sonra çatır', + 'roadtrip.warn.missedLeave.one': 'Təyin etdiyiniz çıxış vaxtından {count} dəq. sonra çatır', 'roadtrip.warn.overnight': 'Növbəti gün', 'roadtrip.spill.title': '{number}-ci gündən', 'roadtrip.spill.departs': 'saat {time}-da yola düşür', diff --git a/shared/src/i18n/az/settings.ts b/shared/src/i18n/az/settings.ts index 0e3757260..5df33bf1e 100644 --- a/shared/src/i18n/az/settings.ts +++ b/shared/src/i18n/az/settings.ts @@ -761,7 +761,9 @@ const settings: TranslationStrings = { 'settings.apiKeys.loadFailed': 'Açarlarınızı yükləmək mümkün olmadı. Yenidən sınamaq üçün səhifəni yeniləyin.', 'settings.apiKeys.limitReached': - 'Hesab üçün maksimum say olan {max} açarınız var. Yeni açar yaratmaq üçün artıq istifadə etmədiyiniz açarlardan birini silin.', + 'Hesab üçün maksimum say olan {count} açarınız var. Yeni açar yaratmaq üçün artıq istifadə etmədiyiniz açarlardan birini silin.', + 'settings.apiKeys.limitReached.one': + 'Hesab üçün maksimum say olan {count} açarınız var. Yeni açar yaratmaq üçün ondan artıq istifadə etmirsinizsə, onu silin.', 'settings.apiKeys.copyFailed': 'Kopyalamaq mümkün olmadı. Mətni seçərək əl ilə kopyalayın.', diff --git a/shared/src/i18n/az/storage.ts b/shared/src/i18n/az/storage.ts index a41b39069..be5df9fb5 100644 --- a/shared/src/i18n/az/storage.ts +++ b/shared/src/i18n/az/storage.ts @@ -136,8 +136,8 @@ const storage: TranslationStrings = { 'storage.usage.legacyNote': 'köhnə foto kitabxanası daxildir', // Category migration (copy → flip → delta sweep) 'storage.migrate.promptTitle': 'Mövcud obyektlər yeni saxlama sisteminə köçürülsün?', - 'storage.migrate.promptLine': - '{category}: {from} sistemindən {to} sisteminə {objects} obyekt ({size})', + 'storage.migrate.promptLine': '{category}: {from} sistemindən {to} sisteminə {count} obyekt ({size})', + 'storage.migrate.promptLine.one': '{category}: {from} sistemindən {to} sisteminə {count} obyekt ({size})', 'storage.migrate.promptLineUnknown': '{category}: {from} sistemindən {to} sisteminə naməlum ölçü (istifadə hələ skan edilməyib)', 'storage.migrate.move': 'Mövcud obyektləri köçür', @@ -149,8 +149,8 @@ const storage: TranslationStrings = { 'storage.migrate.failed': 'Köçürmə uğursuz oldu: {error} — kateqoriya dəyişdirilmədi', 'storage.migrate.cancelled': 'Köçürmə ləğv edildi — heç nə dəyişdirilmədi', - 'storage.migrate.reclaimable': - '{objects} obyekt ({size}) {from} üzərində qalıb — əl ilə geri qazanın', + 'storage.migrate.reclaimable': '{count} obyekt ({size}) {from} üzərində qalıb, əl ilə geri qazanın', + 'storage.migrate.reclaimable.one': '{count} obyekt ({size}) {from} üzərində qalıb, əl ilə geri qazanın', 'storage.migrate.cancel': 'Köçürməni ləğv et', 'storage.migrate.promptCancel': 'Ləğv et', 'storage.migrate.queued': 'Növbədədir: {categories}', diff --git a/shared/src/i18n/br/collab.ts b/shared/src/i18n/br/collab.ts index 9b09325cf..fba440f1d 100644 --- a/shared/src/i18n/br/collab.ts +++ b/shared/src/i18n/br/collab.ts @@ -100,7 +100,8 @@ const collab: TranslationStrings = { 'collab.polls.options': 'Opções', 'collab.polls.delete': 'Excluir', 'collab.polls.closedSection': 'Encerradas', - 'collab.chat.imageLimit': 'Podes anexar até {max} imagens por mensagem', + 'collab.chat.imageLimit': 'Podes anexar até {count} imagens por mensagem', + 'collab.chat.imageLimit.one': 'Podes anexar até {count} imagem por mensagem', 'collab.chat.uploading': 'A enviar {percent}%', 'collab.chat.attachImages': 'Anexar imagens', 'collab.chat.attachedImage': 'Imagem anexada', diff --git a/shared/src/i18n/br/dashboard.ts b/shared/src/i18n/br/dashboard.ts index ec063bc02..b078bdfa2 100644 --- a/shared/src/i18n/br/dashboard.ts +++ b/shared/src/i18n/br/dashboard.ts @@ -99,7 +99,8 @@ const dashboard: TranslationStrings = { 'dashboard.useUnsplashPhoto': 'Usar foto do Unsplash por {photographer}', 'dashboard.titleRequired': 'O título é obrigatório', 'dashboard.endDateError': 'A data final deve ser depois da inicial', - 'dashboard.tripTooLong': 'Uma viagem pode ter no máximo {days} dias', + 'dashboard.tripTooLong': 'Uma viagem pode ter no máximo {count} dias', + 'dashboard.tripTooLong.one': 'Uma viagem pode ter no máximo {count} dia', 'dashboard.dateShiftTitle': 'Nova data de início', 'dashboard.dateShiftIntro': 'Você alterou o início desta viagem. Como seus planos devem acompanhar as novas datas?', 'dashboard.dateShiftKeepBookings': 'Manter reservas em suas datas', diff --git a/shared/src/i18n/br/dawarich.ts b/shared/src/i18n/br/dawarich.ts index f5fdfff59..9008427f5 100644 --- a/shared/src/i18n/br/dawarich.ts +++ b/shared/src/i18n/br/dawarich.ts @@ -118,7 +118,8 @@ const dawarich: TranslationStrings = { 'dawarich.accept.confirm.journal': 'Adicionar entrada', 'dawarich.accept.confirm.bucket_list': 'Riscar', 'dawarich.accept.recorded': 'Gravado de {from} até {to}', - 'dawarich.accept.duration': '{minutes} min', + 'dawarich.accept.duration': '{count} min', + 'dawarich.accept.duration.one': '{count} min', 'dawarich.accept.name': 'Nome', 'dawarich.accept.date': 'Data', 'dawarich.accept.from': 'Chegada', @@ -183,7 +184,8 @@ const dawarich: TranslationStrings = { 'dawarich.again': 'Verificar de novo', 'dawarich.bucket.metersAway': 'a {meters} m', 'dawarich.bucket.kilometersAway': 'a {km} km', - 'dawarich.bucket.rule': 'Um desejo conta como alcançado a até {meters} m e após {minutes} minutos no local.', + 'dawarich.bucket.rule': 'Um desejo conta como alcançado a até {meters} m e após {count} minutos no local.', + 'dawarich.bucket.rule.one': 'Um desejo conta como alcançado a até {meters} m e após {count} minuto no local.', 'dawarich.journey.dayStays.one': '{count} estadia do Dawarich', 'dawarich.journey.dayStays.other': '{count} estadias do Dawarich', diff --git a/shared/src/i18n/br/roadtrip.ts b/shared/src/i18n/br/roadtrip.ts index e5cdd5baf..c6a64206b 100644 --- a/shared/src/i18n/br/roadtrip.ts +++ b/shared/src/i18n/br/roadtrip.ts @@ -55,7 +55,8 @@ const roadtrip: TranslationStrings = { 'roadtrip.window.incomplete': 'Todas as rotas de conexão são necessárias para calcular as pausas diárias.', 'roadtrip.window.conflict': 'Um horário fixo conflita com o trajeto e as pausas. Os horários manuais são mantidos; o planejamento automático está pausado.', - 'roadtrip.window.tooLong': 'Esses horários exigiriam mais de {days} dias extras. Escolha um período diário maior.', + 'roadtrip.window.tooLong': 'Esses horários exigiriam mais de {count} dias extras. Escolha um período diário maior.', + 'roadtrip.window.tooLong.one': 'Esses horários exigiriam mais de {count} dia extra. Escolha um período diário maior.', 'roadtrip.mode.roadtrip': 'Viagem de carro', 'roadtrip.mode.days': 'Dias', 'roadtrip.mode.label': 'Visão do plano', @@ -102,8 +103,10 @@ const roadtrip: TranslationStrings = { 'roadtrip.limit.minutes': 'min', 'roadtrip.limit.off': 'desligado', 'roadtrip.limit.blockNote': 'Um bloco = {distance}', - 'roadtrip.limit.echoOver': '{over} de {days} dias acima do seu limite.', - 'roadtrip.limit.echoNone': 'Todos os {days} dias dentro dos limites.', + 'roadtrip.limit.echoOver': '{over} de {count} dias acima do seu limite.', + 'roadtrip.limit.echoOver.one': '{over} de {count} dia acima do seu limite.', + 'roadtrip.limit.echoNone': 'Todos os {count} dias dentro dos limites.', + 'roadtrip.limit.echoNone.one': '{count} dia dentro dos limites.', 'roadtrip.limit.echoDry': '{count} trechos sem parada alcançável.', 'roadtrip.limit.echoDry.one': '{count} trecho sem parada alcançável.', 'roadtrip.limit.echoEmpty': 'Abra uma viagem para ver o efeito.', @@ -273,8 +276,10 @@ const roadtrip: TranslationStrings = { 'roadtrip.stop.computed': 'Calculado a partir do trajeto', 'roadtrip.stop.endIsLeave': 'Na viagem de carro, a partida é neste horário.', 'roadtrip.via.hint': 'Arraste para remodelar a rota, clique com o botão direito para remover', - 'roadtrip.warn.late': 'Chega {minutes} min depois do horário definido', - 'roadtrip.warn.missedLeave': 'Chega {minutes} min depois do horário de partida definido', + 'roadtrip.warn.late': 'Chega {count} min depois do horário definido', + 'roadtrip.warn.late.one': 'Chega {count} min depois do horário definido', + 'roadtrip.warn.missedLeave': 'Chega {count} min depois do horário de partida definido', + 'roadtrip.warn.missedLeave.one': 'Chega {count} min depois do horário de partida definido', 'roadtrip.warn.overnight': 'Dia seguinte', 'roadtrip.spill.title': 'Do dia {number}', 'roadtrip.spill.departs': 'saída {time}', diff --git a/shared/src/i18n/br/settings.ts b/shared/src/i18n/br/settings.ts index e834f77ce..66884fac8 100644 --- a/shared/src/i18n/br/settings.ts +++ b/shared/src/i18n/br/settings.ts @@ -633,7 +633,10 @@ const settings: TranslationStrings = { 'settings.apiKeys.endpoint': 'Endpoint', 'settings.apiKeys.neverUsed': 'nunca usada', 'settings.apiKeys.loadFailed': 'Não foi possível carregar suas chaves. Recarregue a página para tentar de novo.', - 'settings.apiKeys.limitReached': 'Você tem {max} chaves, o máximo por conta. Exclua uma que não usa mais para criar outra.', + 'settings.apiKeys.limitReached': + 'Você tem {count} chaves, o máximo por conta. Exclua uma que não usa mais para criar outra.', + 'settings.apiKeys.limitReached.one': + 'Você tem {count} chave, o máximo por conta. Exclua-a se não a usa mais para criar outra.', 'settings.apiKeys.copyFailed': 'Não foi possível copiar. Selecione o texto e copie manualmente.', 'settings.apiKeys.modal.createTitle': 'Criar chave de API', 'settings.apiKeys.modal.name': 'Nome', diff --git a/shared/src/i18n/br/storage.ts b/shared/src/i18n/br/storage.ts index f780d20f9..51cd4197e 100644 --- a/shared/src/i18n/br/storage.ts +++ b/shared/src/i18n/br/storage.ts @@ -121,7 +121,8 @@ const storage: TranslationStrings = { // Category migration (copy → flip → delta sweep) 'storage.migrate.promptTitle': 'Mover objetos existentes para o novo backend?', - 'storage.migrate.promptLine': '{category}: {objects} objetos ({size}) de {from} para {to}', + 'storage.migrate.promptLine': '{category}: {count} objetos ({size}) de {from} para {to}', + 'storage.migrate.promptLine.one': '{category}: {count} objeto ({size}) de {from} para {to}', 'storage.migrate.promptLineUnknown': '{category}: tamanho desconhecido (uso ainda não calculado) de {from} para {to}', 'storage.migrate.move': 'Mover objetos existentes', 'storage.migrate.routeOnly': 'Apenas rotear novas gravações', @@ -130,7 +131,8 @@ const storage: TranslationStrings = { 'storage.migrate.doneFailures': '{failed} falharam — esses objetos não foram copiados para o novo backend', 'storage.migrate.failed': 'Falha ao mover: {error} — a categoria não foi alterada', 'storage.migrate.cancelled': 'Movimentação cancelada — nada foi alterado', - 'storage.migrate.reclaimable': '{objects} objetos ({size}) permanecem em {from} — recupere manualmente', + 'storage.migrate.reclaimable': '{count} objetos ({size}) permanecem em {from}, recupere manualmente', + 'storage.migrate.reclaimable.one': '{count} objeto ({size}) permanece em {from}, recupere manualmente', 'storage.migrate.cancel': 'Cancelar movimentação', 'storage.migrate.promptCancel': 'Cancelar', 'storage.migrate.queued': 'Na fila: {categories}', diff --git a/shared/src/i18n/ca/collab.ts b/shared/src/i18n/ca/collab.ts index b00d6e105..17a6bd949 100644 --- a/shared/src/i18n/ca/collab.ts +++ b/shared/src/i18n/ca/collab.ts @@ -100,7 +100,8 @@ const collab: TranslationStrings = { 'collab.polls.countdownHoursMinutes': '{h}h {m}m restants', 'collab.polls.countdownMinutes': '{m}m restants', 'collab.polls.clearDeadline': 'Esborra la data límit', - 'collab.chat.imageLimit': 'Pots adjuntar fins a {max} imatges per missatge', + 'collab.chat.imageLimit': 'Pots adjuntar fins a {count} imatges per missatge', + 'collab.chat.imageLimit.one': 'Només pots adjuntar {count} imatge per missatge', 'collab.chat.uploading': 'Pujant {percent} %', 'collab.chat.attachImages': 'Adjunta imatges', 'collab.chat.attachedImage': 'Imatge adjunta', diff --git a/shared/src/i18n/ca/dashboard.ts b/shared/src/i18n/ca/dashboard.ts index 947d72555..1183c26a3 100644 --- a/shared/src/i18n/ca/dashboard.ts +++ b/shared/src/i18n/ca/dashboard.ts @@ -87,7 +87,8 @@ const dashboard: TranslationStrings = { 'dashboard.coverRemoveError': 'Error en eliminar la imatge', 'dashboard.titleRequired': 'El títol és obligatori', 'dashboard.endDateError': "La data de fi ha de ser posterior a la d'inici", - 'dashboard.tripTooLong': 'Un viatge pot durar com a màxim {days} dies', + 'dashboard.tripTooLong': 'Un viatge pot durar com a màxim {count} dies', + 'dashboard.tripTooLong.one': 'Un viatge pot durar com a màxim {count} dia', 'dashboard.greeting.morning': 'Bon dia,', 'dashboard.greeting.afternoon': 'Bona tarda,', 'dashboard.greeting.evening': 'Bona nit,', diff --git a/shared/src/i18n/ca/dawarich.ts b/shared/src/i18n/ca/dawarich.ts index 4803f56dc..fd4d4b2a7 100644 --- a/shared/src/i18n/ca/dawarich.ts +++ b/shared/src/i18n/ca/dawarich.ts @@ -117,7 +117,8 @@ const dawarich: TranslationStrings = { 'dawarich.accept.confirm.journal': 'Afegeix l’entrada', 'dawarich.accept.confirm.bucket_list': 'Marca’l', 'dawarich.accept.recorded': 'Enregistrat des de {from} fins a {to}', - 'dawarich.accept.duration': '{minutes} min', + 'dawarich.accept.duration': '{count} min', + 'dawarich.accept.duration.one': '{count} min', 'dawarich.accept.name': 'Nom', 'dawarich.accept.date': 'Data', 'dawarich.accept.from': 'Arribada', @@ -182,7 +183,8 @@ const dawarich: TranslationStrings = { 'dawarich.again': 'Tornar a comprovar', 'dawarich.bucket.metersAway': 'a {meters} m', 'dawarich.bucket.kilometersAway': 'a {km} km', - 'dawarich.bucket.rule': 'Un desig es considera assolit a menys de {meters} m i després de {minutes} minuts al lloc.', + 'dawarich.bucket.rule': 'Un desig es considera assolit a menys de {meters} m i després de {count} minuts al lloc.', + 'dawarich.bucket.rule.one': 'Un desig es considera assolit a menys de {meters} m i després de {count} minut al lloc.', 'dawarich.journey.dayStays.other': '{count} estades de Dawarich', 'dawarich.journey.dayStays.one': '{count} estada de Dawarich', diff --git a/shared/src/i18n/ca/roadtrip.ts b/shared/src/i18n/ca/roadtrip.ts index 1707df9ad..91e01b637 100644 --- a/shared/src/i18n/ca/roadtrip.ts +++ b/shared/src/i18n/ca/roadtrip.ts @@ -56,7 +56,9 @@ const roadtrip: TranslationStrings = { 'roadtrip.window.conflict': 'Una hora fixa entra en conflicte amb el trajecte i les pauses. Es mantenen les hores manuals; la planificació automàtica està en pausa.', 'roadtrip.window.tooLong': - 'Aquests horaris requereixen més de {days} dies addicionals. Tria una franja diària més llarga.', + 'Aquests horaris requereixen més de {count} dies addicionals. Tria una franja diària més llarga.', + 'roadtrip.window.tooLong.one': + 'Aquests horaris requereixen més de {count} dia addicional. Tria una franja diària més llarga.', 'roadtrip.mode.roadtrip': 'Viatge per carretera', 'roadtrip.mode.days': 'Dies', 'roadtrip.mode.label': 'Vista del pla', @@ -103,8 +105,10 @@ const roadtrip: TranslationStrings = { 'roadtrip.limit.minutes': 'min', 'roadtrip.limit.off': 'desactivat', 'roadtrip.limit.blockNote': 'Un bloc = {distance}', - 'roadtrip.limit.echoOver': '{over} de {days} dies superen el teu límit.', - 'roadtrip.limit.echoNone': 'Els {days} dies són dins dels límits.', + 'roadtrip.limit.echoOver': '{over} de {count} dies superen el teu límit.', + 'roadtrip.limit.echoOver.one': '{over} de {count} dia supera el teu límit.', + 'roadtrip.limit.echoNone': 'Els {count} dies són dins dels límits.', + 'roadtrip.limit.echoNone.one': 'L’únic dia és dins dels límits.', 'roadtrip.limit.echoDry': '{count} trams sense parada assolible.', 'roadtrip.limit.echoDry.one': '{count} tram sense parada assolible.', 'roadtrip.limit.echoEmpty': 'Obre una ruta per veure’n l’efecte.', @@ -276,8 +280,10 @@ const roadtrip: TranslationStrings = { 'roadtrip.stop.computed': 'Calculat a partir del trajecte', 'roadtrip.stop.endIsLeave': 'En el viatge per carretera, se surt a aquesta hora.', 'roadtrip.via.hint': 'Arrossega per remodelar la ruta, clic dret per eliminar', - 'roadtrip.warn.late': 'Arriba {minutes} min després de l’hora fixada', - 'roadtrip.warn.missedLeave': 'Arriba {minutes} min després de l’hora de sortida fixada', + 'roadtrip.warn.late': 'Arriba {count} min després de l’hora fixada', + 'roadtrip.warn.late.one': 'Arriba {count} min després de l’hora fixada', + 'roadtrip.warn.missedLeave': 'Arriba {count} min després de l’hora de sortida fixada', + 'roadtrip.warn.missedLeave.one': 'Arriba {count} min després de l’hora de sortida fixada', 'roadtrip.warn.overnight': 'Dia següent', 'roadtrip.spill.title': 'Del dia {number}', 'roadtrip.spill.departs': 'surt {time}', diff --git a/shared/src/i18n/ca/settings.ts b/shared/src/i18n/ca/settings.ts index 1f520c088..465b23b93 100644 --- a/shared/src/i18n/ca/settings.ts +++ b/shared/src/i18n/ca/settings.ts @@ -638,7 +638,9 @@ const settings: TranslationStrings = { 'settings.apiKeys.loadFailed': "No s'han pogut carregar les teves claus. Torna a carregar la pàgina per tornar-ho a provar.", 'settings.apiKeys.limitReached': - "Tens {max} claus, el màxim per compte. Esborra'n una que ja no facis servir per crear-ne una altra.", + "Tens {count} claus, el màxim per compte. Esborra'n una que ja no facis servir per crear-ne una altra.", + 'settings.apiKeys.limitReached.one': + 'Tens {count} clau, el màxim per compte. Esborra-la si ja no la fas servir per crear-ne una altra.', 'settings.apiKeys.copyFailed': "No s'ha pogut copiar. Selecciona el text i copia'l a mà.", 'settings.apiKeys.modal.createTitle': 'Crea una clau API', 'settings.apiKeys.modal.name': 'Nom', diff --git a/shared/src/i18n/ca/storage.ts b/shared/src/i18n/ca/storage.ts index 704277fd0..c119cd342 100644 --- a/shared/src/i18n/ca/storage.ts +++ b/shared/src/i18n/ca/storage.ts @@ -125,7 +125,8 @@ const storage: TranslationStrings = { // Category migration (copy → flip → delta sweep) 'storage.migrate.promptTitle': 'Vols moure els objectes existents al nou backend?', - 'storage.migrate.promptLine': '{category}: {objects} objectes ({size}) de {from} a {to}', + 'storage.migrate.promptLine': '{category}: {count} objectes ({size}) de {from} a {to}', + 'storage.migrate.promptLine.one': '{category}: {count} objecte ({size}) de {from} a {to}', 'storage.migrate.promptLineUnknown': "{category}: mida desconeguda (encara no s'ha calculat l'ús) de {from} a {to}", 'storage.migrate.move': 'Mou els objectes existents', 'storage.migrate.routeOnly': 'Només enruta les escriptures noves', @@ -134,7 +135,8 @@ const storage: TranslationStrings = { 'storage.migrate.doneFailures': "{failed} han fallat — aquests objectes no s'han copiat al nou backend", 'storage.migrate.failed': "Ha fallat el trasllat: {error} — la categoria no s'ha canviat", 'storage.migrate.cancelled': "Trasllat cancel·lat — no s'ha canviat res", - 'storage.migrate.reclaimable': "{objects} objectes ({size}) romanen a {from} — recupera'ls manualment", + 'storage.migrate.reclaimable': "{count} objectes ({size}) romanen a {from}, recupera'ls manualment", + 'storage.migrate.reclaimable.one': "{count} objecte ({size}) roman a {from}, recupera'l manualment", 'storage.migrate.cancel': 'Cancel·la el trasllat', 'storage.migrate.promptCancel': 'Cancel·la', 'storage.migrate.queued': 'En cua: {categories}', diff --git a/shared/src/i18n/cs/collab.ts b/shared/src/i18n/cs/collab.ts index 65f98ae71..502364e35 100644 --- a/shared/src/i18n/cs/collab.ts +++ b/shared/src/i18n/cs/collab.ts @@ -104,7 +104,9 @@ const collab: TranslationStrings = { 'collab.polls.options': 'Možnosti', 'collab.polls.delete': 'Smazat', 'collab.polls.closedSection': 'Uzavřené', - 'collab.chat.imageLimit': 'K jedné zprávě můžete připojit nejvýše {max} obrázků', + 'collab.chat.imageLimit': 'K jedné zprávě můžete připojit nejvýše {count} obrázků', + 'collab.chat.imageLimit.one': 'K jedné zprávě můžete připojit jen {count} obrázek', + 'collab.chat.imageLimit.few': 'K jedné zprávě můžete připojit nejvýše {count} obrázky', 'collab.chat.uploading': 'Nahrávání {percent} %', 'collab.chat.attachImages': 'Připojit obrázky', 'collab.chat.attachedImage': 'Připojený obrázek', diff --git a/shared/src/i18n/cs/dashboard.ts b/shared/src/i18n/cs/dashboard.ts index 8b217341a..3a0c562dd 100644 --- a/shared/src/i18n/cs/dashboard.ts +++ b/shared/src/i18n/cs/dashboard.ts @@ -106,7 +106,9 @@ const dashboard: TranslationStrings = { 'dashboard.useUnsplashPhoto': 'Použít fotku z Unsplash od {photographer}', 'dashboard.titleRequired': 'Název je povinný', 'dashboard.endDateError': 'Datum konce musí být po datu začátku', - 'dashboard.tripTooLong': 'Cesta může trvat nejvýše {days} dní', + 'dashboard.tripTooLong': 'Cesta může trvat nejvýše {count} dní', + 'dashboard.tripTooLong.one': 'Cesta může trvat nejvýše {count} den', + 'dashboard.tripTooLong.few': 'Cesta může trvat nejvýše {count} dny', 'dashboard.dateShiftTitle': 'Nové datum začátku', 'dashboard.dateShiftIntro': 'Změnili jste začátek této cesty. Jak se mají vaše plány přizpůsobit novým termínům?', 'dashboard.dateShiftKeepBookings': 'Ponechat rezervace v původních termínech', diff --git a/shared/src/i18n/cs/dawarich.ts b/shared/src/i18n/cs/dawarich.ts index f27a05a75..1e6a22e37 100644 --- a/shared/src/i18n/cs/dawarich.ts +++ b/shared/src/i18n/cs/dawarich.ts @@ -121,7 +121,9 @@ const dawarich: TranslationStrings = { 'dawarich.accept.confirm.journal': 'Přidat záznam', 'dawarich.accept.confirm.bucket_list': 'Odškrtnout', 'dawarich.accept.recorded': 'Zaznamenáno od {from} do {to}', - 'dawarich.accept.duration': '{minutes} min', + 'dawarich.accept.duration': '{count} min', + 'dawarich.accept.duration.one': '{count} min', + 'dawarich.accept.duration.few': '{count} min', 'dawarich.accept.name': 'Název', 'dawarich.accept.date': 'Datum', 'dawarich.accept.from': 'Příchod', @@ -193,7 +195,9 @@ const dawarich: TranslationStrings = { 'dawarich.again': 'Zkontrolovat znovu', 'dawarich.bucket.metersAway': '{meters} m daleko', 'dawarich.bucket.kilometersAway': '{km} km daleko', - 'dawarich.bucket.rule': 'Přání se počítá jako splněné do {meters} m a po {minutes} minutách na místě.', + 'dawarich.bucket.rule': 'Přání se počítá jako splněné do {meters} m a po {count} minutách na místě.', + 'dawarich.bucket.rule.one': 'Přání se počítá jako splněné do {meters} m a po {count} minutě na místě.', + 'dawarich.bucket.rule.few': 'Přání se počítá jako splněné do {meters} m a po {count} minutách na místě.', 'dawarich.journey.dayStays.other': '{count} pobytů z Dawarichu', 'dawarich.journey.dayStays.one': '{count} pobyt z Dawarichu', 'dawarich.journey.dayStays.few': '{count} pobyty z Dawarichu', diff --git a/shared/src/i18n/cs/roadtrip.ts b/shared/src/i18n/cs/roadtrip.ts index 44f78b610..39c3afbf9 100644 --- a/shared/src/i18n/cs/roadtrip.ts +++ b/shared/src/i18n/cs/roadtrip.ts @@ -55,7 +55,9 @@ const roadtrip: TranslationStrings = { 'roadtrip.window.incomplete': 'Denní přestávky lze spočítat až po získání všech navazujících tras.', 'roadtrip.window.conflict': 'Pevný čas je v rozporu s jízdou a přestávkami. Ruční časy zůstávají zachovány; automatické plánování je pozastaveno.', - 'roadtrip.window.tooLong': 'Tyto časy vyžadují více než {days} dalších dní. Zvolte delší denní interval.', + 'roadtrip.window.tooLong': 'Tyto časy vyžadují více než {count} dalších dní. Zvolte delší denní interval.', + 'roadtrip.window.tooLong.one': 'Tyto časy vyžadují více než {count} další den. Zvolte delší denní interval.', + 'roadtrip.window.tooLong.few': 'Tyto časy vyžadují více než {count} další dny. Zvolte delší denní interval.', 'roadtrip.mode.roadtrip': 'Cesta autem', 'roadtrip.mode.days': 'Dny', 'roadtrip.mode.label': 'Zobrazení plánu', @@ -103,8 +105,12 @@ const roadtrip: TranslationStrings = { 'roadtrip.limit.minutes': 'min', 'roadtrip.limit.off': 'vypnuto', 'roadtrip.limit.blockNote': 'Jeden blok = {distance}', - 'roadtrip.limit.echoOver': '{over} z {days} dnů nad tvým limitem.', - 'roadtrip.limit.echoNone': 'Všech {days} dnů je v limitech.', + 'roadtrip.limit.echoOver': '{over} z {count} dnů nad tvým limitem.', + 'roadtrip.limit.echoOver.one': '{over} z {count} dne nad tvým limitem.', + 'roadtrip.limit.echoOver.few': '{over} z {count} dnů nad tvým limitem.', + 'roadtrip.limit.echoNone': 'Všech {count} dnů je v limitech.', + 'roadtrip.limit.echoNone.one': 'Jediný den je v limitech.', + 'roadtrip.limit.echoNone.few': 'Všechny {count} dny jsou v limitech.', 'roadtrip.limit.echoDry': '{count} úseků bez dosažitelné zastávky.', 'roadtrip.limit.echoDry.one': '{count} úsek bez dosažitelné zastávky.', 'roadtrip.limit.echoDry.few': '{count} úseky bez dosažitelné zastávky.', @@ -281,8 +287,12 @@ const roadtrip: TranslationStrings = { 'roadtrip.stop.computed': 'Vypočteno z doby jízdy', 'roadtrip.stop.endIsLeave': 'Na cestě autem se v tento čas odjíždí.', 'roadtrip.via.hint': 'Tažením změníte trasu, pravým tlačítkem odeberete', - 'roadtrip.warn.late': 'Příjezd {minutes} min po nastaveném čase', - 'roadtrip.warn.missedLeave': 'Příjezd {minutes} min po nastaveném čase odjezdu', + 'roadtrip.warn.late': 'Příjezd {count} min po nastaveném čase', + 'roadtrip.warn.late.one': 'Příjezd {count} min po nastaveném čase', + 'roadtrip.warn.late.few': 'Příjezd {count} min po nastaveném čase', + 'roadtrip.warn.missedLeave': 'Příjezd {count} min po nastaveném čase odjezdu', + 'roadtrip.warn.missedLeave.one': 'Příjezd {count} min po nastaveném čase odjezdu', + 'roadtrip.warn.missedLeave.few': 'Příjezd {count} min po nastaveném čase odjezdu', 'roadtrip.warn.overnight': 'Následující den', 'roadtrip.spill.title': 'Ze dne {number}', 'roadtrip.spill.departs': 'odjezd {time}', diff --git a/shared/src/i18n/cs/settings.ts b/shared/src/i18n/cs/settings.ts index 21c88c341..a7707ac5c 100644 --- a/shared/src/i18n/cs/settings.ts +++ b/shared/src/i18n/cs/settings.ts @@ -628,7 +628,12 @@ const settings: TranslationStrings = { 'settings.apiKeys.endpoint': 'Endpoint', 'settings.apiKeys.neverUsed': 'nikdy nepoužit', 'settings.apiKeys.loadFailed': 'Klíče se nepodařilo načíst. Obnov stránku a zkus to znovu.', - 'settings.apiKeys.limitReached': 'Máš {max} klíčů, víc jeden účet mít nemůže. Smaž klíč, který už nepotřebuješ, a vytvoř nový.', + 'settings.apiKeys.limitReached': + 'Máš {count} klíčů, víc jeden účet mít nemůže. Smaž klíč, který už nepotřebuješ, a vytvoř nový.', + 'settings.apiKeys.limitReached.one': + 'Máš {count} klíč, víc jeden účet mít nemůže. Smaž ho, pokud ho už nepotřebuješ, a vytvoř nový.', + 'settings.apiKeys.limitReached.few': + 'Máš {count} klíče, víc jeden účet mít nemůže. Smaž klíč, který už nepotřebuješ, a vytvoř nový.', 'settings.apiKeys.copyFailed': 'Kopírování se nepodařilo. Označ text a zkopíruj ho ručně.', 'settings.apiKeys.modal.createTitle': 'Vytvořit klíč API', 'settings.apiKeys.modal.name': 'Název', diff --git a/shared/src/i18n/cs/storage.ts b/shared/src/i18n/cs/storage.ts index 76321f601..c3375f545 100644 --- a/shared/src/i18n/cs/storage.ts +++ b/shared/src/i18n/cs/storage.ts @@ -121,7 +121,9 @@ const storage: TranslationStrings = { // Category migration (copy → flip → delta sweep) 'storage.migrate.promptTitle': 'Přesunout stávající objekty do nového backendu?', - 'storage.migrate.promptLine': '{category}: {objects} objektů ({size}) z {from} do {to}', + 'storage.migrate.promptLine': '{category}: {count} objektů ({size}) z {from} do {to}', + 'storage.migrate.promptLine.one': '{category}: {count} objekt ({size}) z {from} do {to}', + 'storage.migrate.promptLine.few': '{category}: {count} objekty ({size}) z {from} do {to}', 'storage.migrate.promptLineUnknown': '{category}: neznámá velikost (využití ještě nebylo vypočteno) z {from} do {to}', 'storage.migrate.move': 'Přesunout stávající objekty', 'storage.migrate.routeOnly': 'Pouze směrovat nové zápisy', @@ -130,7 +132,9 @@ const storage: TranslationStrings = { 'storage.migrate.doneFailures': '{failed} se nezdařilo — tyto objekty nebyly zkopírovány do nového backendu', 'storage.migrate.failed': 'Přesun selhal: {error} — kategorie nebyla přepnuta', 'storage.migrate.cancelled': 'Přesun zrušen — nic nebylo přepnuto', - 'storage.migrate.reclaimable': '{objects} objektů ({size}) zůstává na {from} — uvolněte ručně', + 'storage.migrate.reclaimable': '{count} objektů ({size}) zůstává na {from}, uvolněte ručně', + 'storage.migrate.reclaimable.one': '{count} objekt ({size}) zůstává na {from}, uvolněte ručně', + 'storage.migrate.reclaimable.few': '{count} objekty ({size}) zůstávají na {from}, uvolněte ručně', 'storage.migrate.cancel': 'Zrušit přesun', 'storage.migrate.promptCancel': 'Zrušit', 'storage.migrate.queued': 'Ve frontě: {categories}', diff --git a/shared/src/i18n/de/collab.ts b/shared/src/i18n/de/collab.ts index 1e6d68f91..a3aa98a79 100644 --- a/shared/src/i18n/de/collab.ts +++ b/shared/src/i18n/de/collab.ts @@ -100,7 +100,8 @@ const collab: TranslationStrings = { 'collab.polls.options': 'Optionen', 'collab.polls.delete': 'Löschen', 'collab.polls.closedSection': 'Geschlossen', - 'collab.chat.imageLimit': 'Pro Nachricht kannst du bis zu {max} Bilder anhängen', + 'collab.chat.imageLimit': 'Pro Nachricht kannst du bis zu {count} Bilder anhängen', + 'collab.chat.imageLimit.one': 'Pro Nachricht kannst du nur {count} Bild anhängen', 'collab.chat.uploading': 'Wird hochgeladen, {percent} %', 'collab.chat.attachImages': 'Bilder anhängen', 'collab.chat.attachedImage': 'Angehängtes Bild', diff --git a/shared/src/i18n/de/dashboard.ts b/shared/src/i18n/de/dashboard.ts index 60b650b86..89016e0b8 100644 --- a/shared/src/i18n/de/dashboard.ts +++ b/shared/src/i18n/de/dashboard.ts @@ -100,7 +100,8 @@ const dashboard: TranslationStrings = { 'dashboard.useUnsplashPhoto': 'Unsplash-Foto von {photographer} verwenden', 'dashboard.titleRequired': 'Titel ist erforderlich', 'dashboard.endDateError': 'Enddatum muss nach dem Startdatum liegen', - 'dashboard.tripTooLong': 'Eine Reise kann höchstens {days} Tage umfassen', + 'dashboard.tripTooLong': 'Eine Reise kann höchstens {count} Tage umfassen', + 'dashboard.tripTooLong.one': 'Eine Reise kann höchstens {count} Tag umfassen', 'dashboard.dateShiftTitle': 'Neues Startdatum', 'dashboard.dateShiftIntro': 'Du hast den Beginn dieser Reise geändert. Wie sollen deine Pläne den neuen Daten folgen?', diff --git a/shared/src/i18n/de/dawarich.ts b/shared/src/i18n/de/dawarich.ts index ab569805e..fdb94a744 100644 --- a/shared/src/i18n/de/dawarich.ts +++ b/shared/src/i18n/de/dawarich.ts @@ -120,7 +120,8 @@ const dawarich: TranslationStrings = { 'dawarich.accept.confirm.journal': 'Eintrag hinzufügen', 'dawarich.accept.confirm.bucket_list': 'Abhaken', 'dawarich.accept.recorded': 'Aufgezeichnet {from} bis {to}', - 'dawarich.accept.duration': '{minutes} Min.', + 'dawarich.accept.duration': '{count} Min.', + 'dawarich.accept.duration.one': '{count} Min.', 'dawarich.accept.name': 'Name', 'dawarich.accept.date': 'Datum', 'dawarich.accept.from': 'Angekommen', @@ -186,7 +187,8 @@ const dawarich: TranslationStrings = { 'dawarich.again': 'Erneut prüfen', 'dawarich.bucket.metersAway': '{meters} m entfernt', 'dawarich.bucket.kilometersAway': '{km} km entfernt', - 'dawarich.bucket.rule': 'Ein Wunsch gilt ab {meters} m Nähe und {minutes} Minuten vor Ort als erreicht.', + 'dawarich.bucket.rule': 'Ein Wunsch gilt ab {meters} m Nähe und {count} Minuten vor Ort als erreicht.', + 'dawarich.bucket.rule.one': 'Ein Wunsch gilt ab {meters} m Nähe und {count} Minute vor Ort als erreicht.', 'dawarich.journey.dayStays.other': '{count} Aufenthalte aus Dawarich', 'dawarich.journey.dayStays.one': '{count} Aufenthalt aus Dawarich', diff --git a/shared/src/i18n/de/roadtrip.ts b/shared/src/i18n/de/roadtrip.ts index e64996c9f..5fbd8269c 100644 --- a/shared/src/i18n/de/roadtrip.ts +++ b/shared/src/i18n/de/roadtrip.ts @@ -54,7 +54,9 @@ const roadtrip: TranslationStrings = { 'roadtrip.window.conflict': 'Eine feste Uhrzeit passt nicht zu Fahrzeit und Tagespausen. Manuelle Zeiten bleiben unverändert; die automatische Aufteilung pausiert.', 'roadtrip.window.tooLong': - 'Diese Reisezeiten erfordern mehr als {days} zusätzliche Tage. Wähle ein längeres Tagesfenster.', + 'Diese Reisezeiten erfordern mehr als {count} zusätzliche Tage. Wähle ein längeres Tagesfenster.', + 'roadtrip.window.tooLong.one': + 'Diese Reisezeiten erfordern mehr als {count} zusätzlichen Tag. Wähle ein längeres Tagesfenster.', 'roadtrip.mode.roadtrip': 'Roadtrip', 'roadtrip.mode.days': 'Tage', 'roadtrip.mode.label': 'Plan-Ansicht', @@ -101,8 +103,10 @@ const roadtrip: TranslationStrings = { 'roadtrip.limit.minutes': 'Min', 'roadtrip.limit.off': 'aus', 'roadtrip.limit.blockNote': 'Ein Block = {distance}', - 'roadtrip.limit.echoOver': '{over} von {days} Tagen über deinem Limit.', - 'roadtrip.limit.echoNone': 'Alle {days} Tage innerhalb deiner Grenzen.', + 'roadtrip.limit.echoOver': '{over} von {count} Tagen über deinem Limit.', + 'roadtrip.limit.echoOver.one': '{over} von {count} Tag über deinem Limit.', + 'roadtrip.limit.echoNone': 'Alle {count} Tage innerhalb deiner Grenzen.', + 'roadtrip.limit.echoNone.one': 'Der eine Tag liegt innerhalb deiner Grenzen.', 'roadtrip.limit.echoDry': '{count} Abschnitte ohne erreichbaren Stopp.', 'roadtrip.limit.echoDry.one': '{count} Abschnitt ohne erreichbaren Stopp.', 'roadtrip.limit.echoEmpty': 'Öffne einen Roadtrip, um zu sehen, was das bewirkt.', @@ -270,8 +274,10 @@ const roadtrip: TranslationStrings = { 'roadtrip.stop.computed': 'Aus der Fahrzeit gerechnet', 'roadtrip.stop.endIsLeave': 'Im Roadtrip geht die Fahrt zu dieser Zeit weiter.', 'roadtrip.via.hint': 'Ziehen formt die Route um, Rechtsklick entfernt', - 'roadtrip.warn.late': 'Ankunft {minutes} min nach der gesetzten Zeit', - 'roadtrip.warn.missedLeave': 'Ankunft {minutes} min nach der gesetzten Abfahrtszeit', + 'roadtrip.warn.late': 'Ankunft {count} min nach der gesetzten Zeit', + 'roadtrip.warn.late.one': 'Ankunft {count} min nach der gesetzten Zeit', + 'roadtrip.warn.missedLeave': 'Ankunft {count} min nach der gesetzten Abfahrtszeit', + 'roadtrip.warn.missedLeave.one': 'Ankunft {count} min nach der gesetzten Abfahrtszeit', 'roadtrip.warn.overnight': 'Folgetag', 'roadtrip.spill.title': 'Von Tag {number}', 'roadtrip.spill.departs': 'ab {time}', diff --git a/shared/src/i18n/de/settings.ts b/shared/src/i18n/de/settings.ts index 638e6e246..7ffa7e73d 100644 --- a/shared/src/i18n/de/settings.ts +++ b/shared/src/i18n/de/settings.ts @@ -636,7 +636,10 @@ const settings: TranslationStrings = { 'settings.apiKeys.endpoint': 'Endpunkt', 'settings.apiKeys.neverUsed': 'nie genutzt', 'settings.apiKeys.loadFailed': 'Deine Schlüssel konnten nicht geladen werden. Lade die Seite neu, um es noch einmal zu versuchen.', - 'settings.apiKeys.limitReached': 'Du hast {max} Schlüssel, mehr geht pro Konto nicht. Lösche einen, den du nicht mehr brauchst, um einen neuen zu erstellen.', + 'settings.apiKeys.limitReached': + 'Du hast {count} Schlüssel, mehr geht pro Konto nicht. Lösche einen, den du nicht mehr brauchst, um einen neuen zu erstellen.', + 'settings.apiKeys.limitReached.one': + 'Du hast {count} Schlüssel, mehr geht pro Konto nicht. Lösche ihn, wenn du ihn nicht mehr brauchst, um einen neuen zu erstellen.', 'settings.apiKeys.copyFailed': 'Kopieren hat nicht geklappt. Markiere den Text und kopiere ihn von Hand.', 'settings.apiKeys.modal.createTitle': 'API-Schlüssel erstellen', 'settings.apiKeys.modal.name': 'Name', diff --git a/shared/src/i18n/de/storage.ts b/shared/src/i18n/de/storage.ts index 6607156c3..41abbde27 100644 --- a/shared/src/i18n/de/storage.ts +++ b/shared/src/i18n/de/storage.ts @@ -124,7 +124,8 @@ const storage: TranslationStrings = { // Category migration (copy → flip → delta sweep) 'storage.migrate.promptTitle': 'Vorhandene Objekte auf das neue Backend verschieben?', - 'storage.migrate.promptLine': '{category}: {objects} Objekte ({size}) von {from} nach {to}', + 'storage.migrate.promptLine': '{category}: {count} Objekte ({size}) von {from} nach {to}', + 'storage.migrate.promptLine.one': '{category}: {count} Objekt ({size}) von {from} nach {to}', 'storage.migrate.promptLineUnknown': '{category}: unbekannte Größe (Nutzung noch nicht gescannt) von {from} nach {to}', 'storage.migrate.move': 'Vorhandene Objekte verschieben', @@ -134,7 +135,8 @@ const storage: TranslationStrings = { 'storage.migrate.doneFailures': '{failed} fehlgeschlagen — diese Objekte wurden nicht auf das neue Backend kopiert', 'storage.migrate.failed': 'Verschieben fehlgeschlagen: {error} — die Kategorie wurde nicht umgestellt', 'storage.migrate.cancelled': 'Verschieben abgebrochen — nichts wurde umgestellt', - 'storage.migrate.reclaimable': '{objects} Objekte ({size}) verbleiben auf {from} — manuell freigeben', + 'storage.migrate.reclaimable': '{count} Objekte ({size}) verbleiben auf {from}, manuell freigeben', + 'storage.migrate.reclaimable.one': '{count} Objekt ({size}) verbleibt auf {from}, manuell freigeben', 'storage.migrate.cancel': 'Verschieben abbrechen', 'storage.migrate.promptCancel': 'Abbrechen', 'storage.migrate.queued': 'In Warteschlange: {categories}', diff --git a/shared/src/i18n/en/collab.ts b/shared/src/i18n/en/collab.ts index fb6baacab..15fe2a01d 100644 --- a/shared/src/i18n/en/collab.ts +++ b/shared/src/i18n/en/collab.ts @@ -100,7 +100,8 @@ const collab: TranslationStrings = { 'collab.polls.options': 'Options', 'collab.polls.delete': 'Delete', 'collab.polls.closedSection': 'Closed', - 'collab.chat.imageLimit': 'You can attach up to {max} images per message', + 'collab.chat.imageLimit': 'You can attach up to {count} images per message', + 'collab.chat.imageLimit.one': 'You can attach only {count} image per message', 'collab.chat.uploading': 'Uploading {percent}%', 'collab.chat.attachImages': 'Attach images', 'collab.chat.attachedImage': 'Attached image', diff --git a/shared/src/i18n/en/dashboard.ts b/shared/src/i18n/en/dashboard.ts index 0e44e6242..cdfbdd67a 100644 --- a/shared/src/i18n/en/dashboard.ts +++ b/shared/src/i18n/en/dashboard.ts @@ -113,7 +113,8 @@ const dashboard: TranslationStrings = { 'dashboard.useUnsplashPhoto': 'Use Unsplash photo by {photographer}', 'dashboard.titleRequired': 'Title is required', 'dashboard.endDateError': 'End date must be after start date', - 'dashboard.tripTooLong': 'A trip can span at most {days} days', + 'dashboard.tripTooLong': 'A trip can span at most {count} days', + 'dashboard.tripTooLong.one': 'A trip can span at most {count} day', 'dashboard.dateShiftTitle': 'New start date', 'dashboard.dateShiftIntro': 'You changed when this trip starts. How should your plans follow the new dates?', 'dashboard.dateShiftKeepBookings': 'Keep bookings on their dates', diff --git a/shared/src/i18n/en/dawarich.ts b/shared/src/i18n/en/dawarich.ts index 1e0411fdc..5b664feb1 100644 --- a/shared/src/i18n/en/dawarich.ts +++ b/shared/src/i18n/en/dawarich.ts @@ -116,7 +116,8 @@ const dawarich: TranslationStrings = { 'dawarich.accept.confirm.journal': 'Add entry', 'dawarich.accept.confirm.bucket_list': 'Tick it off', 'dawarich.accept.recorded': 'Recorded {from} until {to}', - 'dawarich.accept.duration': '{minutes} min', + 'dawarich.accept.duration': '{count} min', + 'dawarich.accept.duration.one': '{count} min', 'dawarich.accept.name': 'Name', 'dawarich.accept.date': 'Date', 'dawarich.accept.from': 'Arrived', @@ -181,7 +182,8 @@ const dawarich: TranslationStrings = { 'dawarich.again': 'Check again', 'dawarich.bucket.metersAway': '{meters} m away', 'dawarich.bucket.kilometersAway': '{km} km away', - 'dawarich.bucket.rule': 'A wish counts as reached within {meters} m and after {minutes} minutes on the spot.', + 'dawarich.bucket.rule': 'A wish counts as reached within {meters} m and after {count} minutes on the spot.', + 'dawarich.bucket.rule.one': 'A wish counts as reached within {meters} m and after {count} minute on the spot.', 'dawarich.journey.dayStays.other': '{count} stays from Dawarich', 'dawarich.journey.dayStays.one': '{count} stay from Dawarich', diff --git a/shared/src/i18n/en/roadtrip.ts b/shared/src/i18n/en/roadtrip.ts index 58c3a831a..cc81da421 100644 --- a/shared/src/i18n/en/roadtrip.ts +++ b/shared/src/i18n/en/roadtrip.ts @@ -54,7 +54,9 @@ const roadtrip: TranslationStrings = { 'roadtrip.window.conflict': 'A fixed time conflicts with the drive and daily breaks. Manual times are unchanged; automatic scheduling is paused.', 'roadtrip.window.tooLong': - 'These travel times would require more than {days} extra days. Choose a longer daily window.', + 'These travel times would require more than {count} extra days. Choose a longer daily window.', + 'roadtrip.window.tooLong.one': + 'These travel times would require more than {count} extra day. Choose a longer daily window.', 'roadtrip.mode.roadtrip': 'Road trip', 'roadtrip.mode.days': 'Days', 'roadtrip.mode.label': 'Plan view', @@ -101,8 +103,10 @@ const roadtrip: TranslationStrings = { 'roadtrip.limit.minutes': 'min', 'roadtrip.limit.off': 'off', 'roadtrip.limit.blockNote': 'One block = {distance}', - 'roadtrip.limit.echoOver': '{over} of {days} days over your limit.', - 'roadtrip.limit.echoNone': 'All {days} days within your limits.', + 'roadtrip.limit.echoOver': '{over} of {count} days over your limit.', + 'roadtrip.limit.echoOver.one': '{over} of {count} day over your limit.', + 'roadtrip.limit.echoNone': 'All {count} days within your limits.', + 'roadtrip.limit.echoNone.one': 'The one day is within your limits.', 'roadtrip.limit.echoDry': '{count} stretches with no reachable stop.', 'roadtrip.limit.echoDry.one': '{count} stretch with no reachable stop.', 'roadtrip.limit.echoEmpty': 'Open a road trip to see what these do to it.', @@ -266,8 +270,10 @@ const roadtrip: TranslationStrings = { 'roadtrip.stop.computed': 'Calculated from the drive', 'roadtrip.stop.endIsLeave': 'On the road trip, the drive leaves at this time.', 'roadtrip.via.hint': 'Drag to reshape the route, right-click to remove', - 'roadtrip.warn.late': 'Arrives {minutes} min after the time you set', - 'roadtrip.warn.missedLeave': 'Arrives {minutes} min after the time you set to leave', + 'roadtrip.warn.late': 'Arrives {count} min after the time you set', + 'roadtrip.warn.late.one': 'Arrives {count} min after the time you set', + 'roadtrip.warn.missedLeave': 'Arrives {count} min after the time you set to leave', + 'roadtrip.warn.missedLeave.one': 'Arrives {count} min after the time you set to leave', 'roadtrip.warn.overnight': 'Next day', 'roadtrip.spill.title': 'From day {number}', 'roadtrip.spill.departs': 'leaves {time}', diff --git a/shared/src/i18n/en/settings.ts b/shared/src/i18n/en/settings.ts index 1ee65e059..650c12abc 100644 --- a/shared/src/i18n/en/settings.ts +++ b/shared/src/i18n/en/settings.ts @@ -622,7 +622,10 @@ const settings: TranslationStrings = { 'settings.apiKeys.endpoint': 'Endpoint', 'settings.apiKeys.neverUsed': 'never used', 'settings.apiKeys.loadFailed': 'Could not load your keys. Reload the page to try again.', - 'settings.apiKeys.limitReached': 'You have {max} keys, the most an account can hold. Delete one you no longer use to create another.', + 'settings.apiKeys.limitReached': + 'You have {count} keys, the most an account can hold. Delete one you no longer use to create another.', + 'settings.apiKeys.limitReached.one': + 'You have {count} key, the most an account can hold. Delete it if you no longer use it to create another.', 'settings.apiKeys.copyFailed': 'Could not copy. Select the text and copy it by hand.', 'settings.apiKeys.modal.createTitle': 'Create API key', 'settings.apiKeys.modal.name': 'Name', diff --git a/shared/src/i18n/en/storage.ts b/shared/src/i18n/en/storage.ts index 97bcb30ef..4c98fac5e 100644 --- a/shared/src/i18n/en/storage.ts +++ b/shared/src/i18n/en/storage.ts @@ -136,7 +136,8 @@ const storage: TranslationStrings = { // Category migration (copy → flip → delta sweep) 'storage.migrate.promptTitle': 'Move existing objects to the new backend?', - 'storage.migrate.promptLine': '{category}: {objects} objects ({size}) from {from} to {to}', + 'storage.migrate.promptLine': '{category}: {count} objects ({size}) from {from} to {to}', + 'storage.migrate.promptLine.one': '{category}: {count} object ({size}) from {from} to {to}', 'storage.migrate.promptLineUnknown': '{category}: unknown size (no usage scan yet) from {from} to {to}', 'storage.migrate.move': 'Move existing objects', 'storage.migrate.routeOnly': 'Just route new writes', @@ -145,7 +146,8 @@ const storage: TranslationStrings = { 'storage.migrate.doneFailures': '{failed} failed — those objects were not copied to the new backend', 'storage.migrate.failed': 'Move failed: {error} — the category was not switched', 'storage.migrate.cancelled': 'Move cancelled — nothing was switched', - 'storage.migrate.reclaimable': '{objects} objects ({size}) remain on {from} — reclaim manually', + 'storage.migrate.reclaimable': '{count} objects ({size}) remain on {from}, reclaim manually', + 'storage.migrate.reclaimable.one': '{count} object ({size}) remains on {from}, reclaim manually', 'storage.migrate.cancel': 'Cancel move', 'storage.migrate.promptCancel': 'Cancel', 'storage.migrate.queued': 'Queued: {categories}', diff --git a/shared/src/i18n/es/collab.ts b/shared/src/i18n/es/collab.ts index 704dc3269..65ef69bed 100644 --- a/shared/src/i18n/es/collab.ts +++ b/shared/src/i18n/es/collab.ts @@ -100,7 +100,8 @@ const collab: TranslationStrings = { 'collab.polls.options': 'Opciones', 'collab.polls.delete': 'Eliminar', 'collab.polls.closedSection': 'Cerradas', - 'collab.chat.imageLimit': 'Puedes adjuntar hasta {max} imágenes por mensaje', + 'collab.chat.imageLimit': 'Puedes adjuntar hasta {count} imágenes por mensaje', + 'collab.chat.imageLimit.one': 'Solo puedes adjuntar {count} imagen por mensaje', 'collab.chat.uploading': 'Subiendo {percent} %', 'collab.chat.attachImages': 'Adjuntar imágenes', 'collab.chat.attachedImage': 'Imagen adjunta', diff --git a/shared/src/i18n/es/dashboard.ts b/shared/src/i18n/es/dashboard.ts index b5365009a..00ba21568 100644 --- a/shared/src/i18n/es/dashboard.ts +++ b/shared/src/i18n/es/dashboard.ts @@ -99,7 +99,8 @@ const dashboard: TranslationStrings = { 'dashboard.useUnsplashPhoto': 'Usar foto de Unsplash de {photographer}', 'dashboard.titleRequired': 'El título es obligatorio', 'dashboard.endDateError': 'La fecha de fin debe ser posterior a la de inicio', - 'dashboard.tripTooLong': 'Un viaje puede durar como máximo {days} días', + 'dashboard.tripTooLong': 'Un viaje puede durar como máximo {count} días', + 'dashboard.tripTooLong.one': 'Un viaje puede durar como máximo {count} día', 'dashboard.dateShiftTitle': 'Nueva fecha de inicio', 'dashboard.dateShiftIntro': 'Has cambiado cuándo empieza este viaje. ¿Cómo deben seguir tus planes las nuevas fechas?', diff --git a/shared/src/i18n/es/dawarich.ts b/shared/src/i18n/es/dawarich.ts index e0081434d..4157092ac 100644 --- a/shared/src/i18n/es/dawarich.ts +++ b/shared/src/i18n/es/dawarich.ts @@ -118,7 +118,8 @@ const dawarich: TranslationStrings = { 'dawarich.accept.confirm.journal': 'Añadir entrada', 'dawarich.accept.confirm.bucket_list': 'Tacharlo', 'dawarich.accept.recorded': 'Grabado de {from} a {to}', - 'dawarich.accept.duration': '{minutes} min', + 'dawarich.accept.duration': '{count} min', + 'dawarich.accept.duration.one': '{count} min', 'dawarich.accept.name': 'Nombre', 'dawarich.accept.date': 'Fecha', 'dawarich.accept.from': 'Llegada', @@ -183,7 +184,8 @@ const dawarich: TranslationStrings = { 'dawarich.again': 'Volver a comprobar', 'dawarich.bucket.metersAway': 'a {meters} m', 'dawarich.bucket.kilometersAway': 'a {km} km', - 'dawarich.bucket.rule': 'Un deseo cuenta como cumplido a menos de {meters} m y tras {minutes} minutos en el lugar.', + 'dawarich.bucket.rule': 'Un deseo cuenta como cumplido a menos de {meters} m y tras {count} minutos en el lugar.', + 'dawarich.bucket.rule.one': 'Un deseo cuenta como cumplido a menos de {meters} m y tras {count} minuto en el lugar.', 'dawarich.journey.dayStays.other': '{count} estancias de Dawarich', 'dawarich.journey.dayStays.one': '{count} estancia de Dawarich', diff --git a/shared/src/i18n/es/roadtrip.ts b/shared/src/i18n/es/roadtrip.ts index 90cbb693e..cc2fcbb02 100644 --- a/shared/src/i18n/es/roadtrip.ts +++ b/shared/src/i18n/es/roadtrip.ts @@ -56,7 +56,8 @@ const roadtrip: TranslationStrings = { 'roadtrip.window.incomplete': 'Las pausas diarias necesitan todas las rutas de conexión para calcularse.', 'roadtrip.window.conflict': 'Una hora fija entra en conflicto con el trayecto y las pausas. Las horas manuales se conservan; la planificación automática está en pausa.', - 'roadtrip.window.tooLong': 'Estos horarios requieren más de {days} días adicionales. Amplía el horario diario.', + 'roadtrip.window.tooLong': 'Estos horarios requieren más de {count} días adicionales. Amplía el horario diario.', + 'roadtrip.window.tooLong.one': 'Estos horarios requieren más de {count} día adicional. Amplía el horario diario.', 'roadtrip.mode.roadtrip': 'Viaje por carretera', 'roadtrip.mode.days': 'Días', 'roadtrip.mode.label': 'Vista del plan', @@ -103,8 +104,10 @@ const roadtrip: TranslationStrings = { 'roadtrip.limit.minutes': 'min', 'roadtrip.limit.off': 'desactivado', 'roadtrip.limit.blockNote': 'Un bloque = {distance}', - 'roadtrip.limit.echoOver': '{over} de {days} días superan tu límite.', - 'roadtrip.limit.echoNone': 'Los {days} días están dentro de tus límites.', + 'roadtrip.limit.echoOver': '{over} de {count} días superan tu límite.', + 'roadtrip.limit.echoOver.one': '{over} de {count} día supera tu límite.', + 'roadtrip.limit.echoNone': 'Los {count} días están dentro de tus límites.', + 'roadtrip.limit.echoNone.one': 'El único día está dentro de tus límites.', 'roadtrip.limit.echoDry': '{count} tramos sin parada alcanzable.', 'roadtrip.limit.echoDry.one': '{count} tramo sin parada alcanzable.', 'roadtrip.limit.echoEmpty': 'Abre una ruta para ver el efecto.', @@ -274,8 +277,10 @@ const roadtrip: TranslationStrings = { 'roadtrip.stop.computed': 'Calculado a partir del trayecto', 'roadtrip.stop.endIsLeave': 'En el viaje por carretera, se sale a esta hora.', 'roadtrip.via.hint': 'Arrastra para remodelar la ruta, clic derecho para quitar', - 'roadtrip.warn.late': 'Llega {minutes} min después de la hora fijada', - 'roadtrip.warn.missedLeave': 'Llega {minutes} min después de la hora de salida fijada', + 'roadtrip.warn.late': 'Llega {count} min después de la hora fijada', + 'roadtrip.warn.late.one': 'Llega {count} min después de la hora fijada', + 'roadtrip.warn.missedLeave': 'Llega {count} min después de la hora de salida fijada', + 'roadtrip.warn.missedLeave.one': 'Llega {count} min después de la hora de salida fijada', 'roadtrip.warn.overnight': 'Día siguiente', 'roadtrip.spill.title': 'Del día {number}', 'roadtrip.spill.departs': 'sale {time}', diff --git a/shared/src/i18n/es/settings.ts b/shared/src/i18n/es/settings.ts index 3bcbbe06a..fad331426 100644 --- a/shared/src/i18n/es/settings.ts +++ b/shared/src/i18n/es/settings.ts @@ -633,7 +633,10 @@ const settings: TranslationStrings = { 'settings.apiKeys.endpoint': 'Endpoint', 'settings.apiKeys.neverUsed': 'nunca usada', 'settings.apiKeys.loadFailed': 'No se pudieron cargar tus claves. Recarga la página para volver a intentarlo.', - 'settings.apiKeys.limitReached': 'Tienes {max} claves, el máximo por cuenta. Elimina una que ya no uses para crear otra.', + 'settings.apiKeys.limitReached': + 'Tienes {count} claves, el máximo por cuenta. Elimina una que ya no uses para crear otra.', + 'settings.apiKeys.limitReached.one': + 'Tienes {count} clave, el máximo por cuenta. Elimínala si ya no la usas para crear otra.', 'settings.apiKeys.copyFailed': 'No se pudo copiar. Selecciona el texto y cópialo a mano.', 'settings.apiKeys.modal.createTitle': 'Crear clave API', 'settings.apiKeys.modal.name': 'Nombre', diff --git a/shared/src/i18n/es/storage.ts b/shared/src/i18n/es/storage.ts index be28e822c..e6a6d8019 100644 --- a/shared/src/i18n/es/storage.ts +++ b/shared/src/i18n/es/storage.ts @@ -126,7 +126,8 @@ const storage: TranslationStrings = { // Category migration (copy → flip → delta sweep) 'storage.migrate.promptTitle': '¿Mover los objetos existentes al nuevo backend?', - 'storage.migrate.promptLine': '{category}: {objects} objetos ({size}) de {from} a {to}', + 'storage.migrate.promptLine': '{category}: {count} objetos ({size}) de {from} a {to}', + 'storage.migrate.promptLine.one': '{category}: {count} objeto ({size}) de {from} a {to}', 'storage.migrate.promptLineUnknown': '{category}: tamaño desconocido (uso aún no calculado) de {from} a {to}', 'storage.migrate.move': 'Mover objetos existentes', 'storage.migrate.routeOnly': 'Solo enrutar las escrituras nuevas', @@ -135,7 +136,8 @@ const storage: TranslationStrings = { 'storage.migrate.doneFailures': '{failed} fallaron — esos objetos no se copiaron al nuevo backend', 'storage.migrate.failed': 'Error al mover: {error} — la categoría no se cambió', 'storage.migrate.cancelled': 'Movimiento cancelado — no se cambió nada', - 'storage.migrate.reclaimable': '{objects} objetos ({size}) permanecen en {from} — recupéralos manualmente', + 'storage.migrate.reclaimable': '{count} objetos ({size}) permanecen en {from}, recupéralos manualmente', + 'storage.migrate.reclaimable.one': '{count} objeto ({size}) permanece en {from}, recupéralo manualmente', 'storage.migrate.cancel': 'Cancelar movimiento', 'storage.migrate.promptCancel': 'Cancelar', 'storage.migrate.queued': 'En cola: {categories}', diff --git a/shared/src/i18n/et/collab.ts b/shared/src/i18n/et/collab.ts index df6eae0ff..26485420d 100644 --- a/shared/src/i18n/et/collab.ts +++ b/shared/src/i18n/et/collab.ts @@ -100,7 +100,8 @@ const collab: TranslationStrings = { 'collab.polls.options': 'Valikud', 'collab.polls.delete': 'Kustuta', 'collab.polls.closedSection': 'Suletud', - 'collab.chat.imageLimit': 'Ühele sõnumile saad lisada kuni {max} pilti', + 'collab.chat.imageLimit': 'Ühele sõnumile saad lisada kuni {count} pilti', + 'collab.chat.imageLimit.one': 'Ühele sõnumile saad lisada vaid {count} pildi', 'collab.chat.uploading': 'Üleslaadimine {percent}%', 'collab.chat.attachImages': 'Lisa pildid', 'collab.chat.attachedImage': 'Lisatud pilt', diff --git a/shared/src/i18n/et/dashboard.ts b/shared/src/i18n/et/dashboard.ts index bc406da92..5c9f4f9a0 100644 --- a/shared/src/i18n/et/dashboard.ts +++ b/shared/src/i18n/et/dashboard.ts @@ -113,7 +113,8 @@ const dashboard: TranslationStrings = { 'dashboard.useUnsplashPhoto': 'Kasuta Unsplashi fotot autorilt {photographer}', 'dashboard.titleRequired': 'Pealkiri on kohustuslik', 'dashboard.endDateError': 'Lõppkuupäev peab olema alguskuupäevast hilisem', - 'dashboard.tripTooLong': 'Reis võib kesta kuni {days} päeva', + 'dashboard.tripTooLong': 'Reis võib kesta kuni {count} päeva', + 'dashboard.tripTooLong.one': 'Reis võib kesta kuni {count} päev', 'dashboard.dateShiftTitle': 'Uus alguskuupäev', 'dashboard.dateShiftIntro': 'Muutsid reisi algust. Kuidas peaksid plaanid uute kuupäevadega kohanema?', 'dashboard.dateShiftKeepBookings': 'Jäta broneeringud oma kuupäevadele', diff --git a/shared/src/i18n/et/dawarich.ts b/shared/src/i18n/et/dawarich.ts index da5ce5e2a..7c36789c2 100644 --- a/shared/src/i18n/et/dawarich.ts +++ b/shared/src/i18n/et/dawarich.ts @@ -119,7 +119,8 @@ const dawarich: TranslationStrings = { 'dawarich.accept.confirm.journal': 'Lisa sissekanne', 'dawarich.accept.confirm.bucket_list': 'Märgi täidetuks', 'dawarich.accept.recorded': 'Salvestatud {from} kuni {to}', - 'dawarich.accept.duration': '{minutes} min', + 'dawarich.accept.duration': '{count} min', + 'dawarich.accept.duration.one': '{count} min', 'dawarich.accept.name': 'Nimi', 'dawarich.accept.date': 'Kuupäev', 'dawarich.accept.from': 'Saabusid', @@ -184,7 +185,9 @@ const dawarich: TranslationStrings = { 'dawarich.again': 'Kontrolli uuesti', 'dawarich.bucket.metersAway': '{meters} m kaugusel', 'dawarich.bucket.kilometersAway': '{km} km kaugusel', - 'dawarich.bucket.rule': 'Soov loetakse täidetuks, kui viibid vähemalt {minutes} minutit kohast {meters} m raadiuses.', + 'dawarich.bucket.rule': 'Soov loetakse täidetuks, kui viibid vähemalt {count} minutit kohast {meters} m raadiuses.', + 'dawarich.bucket.rule.one': + 'Soov loetakse täidetuks, kui viibid vähemalt {count} minuti kohast {meters} m raadiuses.', 'dawarich.journey.dayStays.other': '{count} peatumist Dawarichist', 'dawarich.journey.dayStays.one': '{count} peatumine Dawarichist', diff --git a/shared/src/i18n/et/roadtrip.ts b/shared/src/i18n/et/roadtrip.ts index f5949a71e..7b0fe7d4a 100644 --- a/shared/src/i18n/et/roadtrip.ts +++ b/shared/src/i18n/et/roadtrip.ts @@ -52,7 +52,8 @@ const roadtrip: TranslationStrings = { 'roadtrip.window.incomplete': 'Päevaseid pause ei saa arvutada, kuni kõik ühendavad marsruudid on saadaval.', 'roadtrip.window.conflict': 'Kindel kellaaeg on vastuolus sõidu ja päevapausidega. Käsitsi määratud ajad ei muutu; automaatne ajastamine on peatatud.', - 'roadtrip.window.tooLong': 'Nende sõiduaegadega oleks vaja üle {days} lisapäeva. Vali pikem päevane ajavahemik.', + 'roadtrip.window.tooLong': 'Nende sõiduaegadega oleks vaja üle {count} lisapäeva. Vali pikem päevane ajavahemik.', + 'roadtrip.window.tooLong.one': 'Nende sõiduaegadega oleks vaja üle {count} lisapäeva. Vali pikem päevane ajavahemik.', 'roadtrip.mode.roadtrip': 'Autoreis', 'roadtrip.mode.days': 'Päevad', 'roadtrip.mode.label': 'Plaanivaade', @@ -99,8 +100,10 @@ const roadtrip: TranslationStrings = { 'roadtrip.limit.minutes': 'min', 'roadtrip.limit.off': 'väljas', 'roadtrip.limit.blockNote': 'Üks plokk = {distance}', - 'roadtrip.limit.echoOver': '{over} päeva {days}-st ületab sinu piirangu.', - 'roadtrip.limit.echoNone': 'Kõik {days} päeva jäävad sinu piirangutesse.', + 'roadtrip.limit.echoOver': '{over} päeva {count}-st ületab sinu piirangu.', + 'roadtrip.limit.echoOver.one': '{over} päeva {count}-st ületab sinu piirangu.', + 'roadtrip.limit.echoNone': 'Kõik {count} päeva jäävad sinu piirangutesse.', + 'roadtrip.limit.echoNone.one': 'Ainus päev jääb sinu piirangutesse.', 'roadtrip.limit.echoDry': '{count} lõiku ilma kättesaadava peatuseta.', 'roadtrip.limit.echoDry.one': '{count} lõik ilma kättesaadava peatuseta.', 'roadtrip.limit.echoEmpty': 'Ava autoreis, et näha nende mõju.', @@ -266,8 +269,10 @@ const roadtrip: TranslationStrings = { 'roadtrip.stop.computed': 'Arvutatud sõidu põhjal', 'roadtrip.stop.endIsLeave': 'Autoreisil algab sõit sel kellaajal.', 'roadtrip.via.hint': 'Marsruudi muutmiseks lohista, eemaldamiseks tee paremklõps', - 'roadtrip.warn.late': 'Saabub {minutes} minutit pärast määratud aega', - 'roadtrip.warn.missedLeave': 'Saabub {minutes} minutit pärast määratud väljumisaega', + 'roadtrip.warn.late': 'Saabub {count} minutit pärast määratud aega', + 'roadtrip.warn.late.one': 'Saabub {count} minut pärast määratud aega', + 'roadtrip.warn.missedLeave': 'Saabub {count} minutit pärast määratud väljumisaega', + 'roadtrip.warn.missedLeave.one': 'Saabub {count} minut pärast määratud väljumisaega', 'roadtrip.warn.overnight': 'Järgmine päev', 'roadtrip.spill.title': 'Päevast {number}', 'roadtrip.spill.departs': 'väljub {time}', diff --git a/shared/src/i18n/et/settings.ts b/shared/src/i18n/et/settings.ts index 81a92ee66..61e0bef43 100644 --- a/shared/src/i18n/et/settings.ts +++ b/shared/src/i18n/et/settings.ts @@ -633,7 +633,9 @@ const settings: TranslationStrings = { 'settings.apiKeys.neverUsed': 'pole kunagi kasutatud', 'settings.apiKeys.loadFailed': 'Võtmeid ei saanud laadida. Uuesti proovimiseks laadi leht uuesti.', 'settings.apiKeys.limitReached': - 'Sul on {max} võtit — konto suurim lubatud arv. Uue loomiseks kustuta võti, mida enam ei kasuta.', + 'Sul on {count} võtit, konto suurim lubatud arv. Uue loomiseks kustuta võti, mida enam ei kasuta.', + 'settings.apiKeys.limitReached.one': + 'Sul on {count} võti, konto suurim lubatud arv. Uue loomiseks kustuta see, kui sa seda enam ei kasuta.', 'settings.apiKeys.copyFailed': 'Kopeerimine ebaõnnestus. Vali tekst ja kopeeri käsitsi.', 'settings.apiKeys.modal.createTitle': 'Loo API-võti', 'settings.apiKeys.modal.name': 'Nimi', diff --git a/shared/src/i18n/et/storage.ts b/shared/src/i18n/et/storage.ts index d237cae62..e67ce89b5 100644 --- a/shared/src/i18n/et/storage.ts +++ b/shared/src/i18n/et/storage.ts @@ -139,7 +139,8 @@ const storage: TranslationStrings = { // Category migration (copy → flip → delta sweep) 'storage.migrate.promptTitle': 'Kas teisaldada olemasolevad objektid uude taustsüsteemi?', - 'storage.migrate.promptLine': '{category}: {objects} objekti ({size}), {from} → {to}', + 'storage.migrate.promptLine': '{category}: {count} objekti ({size}), {from} → {to}', + 'storage.migrate.promptLine.one': '{category}: {count} objekt ({size}), {from} → {to}', 'storage.migrate.promptLineUnknown': '{category}: suurus teadmata (kasutust pole veel kontrollitud), {from} → {to}', 'storage.migrate.move': 'Teisalda olemasolevad objektid', 'storage.migrate.routeOnly': 'Suuna ainult uued kirjutused', @@ -148,7 +149,8 @@ const storage: TranslationStrings = { 'storage.migrate.doneFailures': '{failed} ebaõnnestus — neid objekte ei kopeeritud uude taustsüsteemi', 'storage.migrate.failed': 'Teisaldamine ebaõnnestus: {error} — kategooriat ei suunatud ümber', 'storage.migrate.cancelled': 'Teisaldamine tühistatud — midagi ei suunatud ümber', - 'storage.migrate.reclaimable': '{objects} objekti ({size}) jäid taustsüsteemi {from} — vabasta ruum käsitsi', + 'storage.migrate.reclaimable': '{count} objekti ({size}) jäid taustsüsteemi {from}, vabasta ruum käsitsi', + 'storage.migrate.reclaimable.one': '{count} objekt ({size}) jäi taustsüsteemi {from}, vabasta ruum käsitsi', 'storage.migrate.cancel': 'Tühista teisaldamine', 'storage.migrate.promptCancel': 'Tühista', 'storage.migrate.queued': 'Järjekorras: {categories}', diff --git a/shared/src/i18n/fr/collab.ts b/shared/src/i18n/fr/collab.ts index a69476aef..979d27321 100644 --- a/shared/src/i18n/fr/collab.ts +++ b/shared/src/i18n/fr/collab.ts @@ -100,7 +100,8 @@ const collab: TranslationStrings = { 'collab.polls.options': 'Options', 'collab.polls.delete': 'Supprimer', 'collab.polls.closedSection': 'Fermés', - 'collab.chat.imageLimit': 'Vous pouvez joindre jusqu’à {max} images par message', + 'collab.chat.imageLimit': 'Vous pouvez joindre jusqu’à {count} images par message', + 'collab.chat.imageLimit.one': 'Vous pouvez joindre jusqu’à {count} image par message', 'collab.chat.uploading': 'Envoi {percent} %', 'collab.chat.attachImages': 'Joindre des images', 'collab.chat.attachedImage': 'Image jointe', diff --git a/shared/src/i18n/fr/dashboard.ts b/shared/src/i18n/fr/dashboard.ts index 0e969d96e..ef282fc3d 100644 --- a/shared/src/i18n/fr/dashboard.ts +++ b/shared/src/i18n/fr/dashboard.ts @@ -101,7 +101,8 @@ const dashboard: TranslationStrings = { 'dashboard.useUnsplashPhoto': 'Utiliser la photo Unsplash de {photographer}', 'dashboard.titleRequired': 'Le titre est obligatoire', 'dashboard.endDateError': 'La date de fin doit être postérieure à la date de début', - 'dashboard.tripTooLong': 'Un voyage ne peut pas dépasser {days} jours', + 'dashboard.tripTooLong': 'Un voyage ne peut pas dépasser {count} jours', + 'dashboard.tripTooLong.one': 'Un voyage ne peut pas dépasser {count} jour', 'dashboard.dateShiftTitle': 'Nouvelle date de début', 'dashboard.dateShiftIntro': 'Vous avez modifié la date de début de ce voyage. Comment vos plans doivent-ils suivre les nouvelles dates ?', diff --git a/shared/src/i18n/fr/dawarich.ts b/shared/src/i18n/fr/dawarich.ts index 4c1045a98..db7739900 100644 --- a/shared/src/i18n/fr/dawarich.ts +++ b/shared/src/i18n/fr/dawarich.ts @@ -119,7 +119,8 @@ const dawarich: TranslationStrings = { 'dawarich.accept.confirm.journal': 'Ajouter l’entrée', 'dawarich.accept.confirm.bucket_list': 'Le cocher', 'dawarich.accept.recorded': 'Enregistré du {from} au {to}', - 'dawarich.accept.duration': '{minutes} min', + 'dawarich.accept.duration': '{count} min', + 'dawarich.accept.duration.one': '{count} min', 'dawarich.accept.name': 'Nom', 'dawarich.accept.date': 'Date', 'dawarich.accept.from': 'Arrivée', @@ -185,7 +186,8 @@ const dawarich: TranslationStrings = { 'dawarich.again': 'Vérifier à nouveau', 'dawarich.bucket.metersAway': 'à {meters} m', 'dawarich.bucket.kilometersAway': 'à {km} km', - 'dawarich.bucket.rule': 'Une envie est atteinte à moins de {meters} m et après {minutes} minutes sur place.', + 'dawarich.bucket.rule': 'Une envie est atteinte à moins de {meters} m et après {count} minutes sur place.', + 'dawarich.bucket.rule.one': 'Une envie est atteinte à moins de {meters} m et après {count} minute sur place.', 'dawarich.journey.dayStays.other': '{count} séjours issus de Dawarich', 'dawarich.journey.dayStays.one': '{count} séjour issu de Dawarich', diff --git a/shared/src/i18n/fr/roadtrip.ts b/shared/src/i18n/fr/roadtrip.ts index 0079c8cdc..d1bd752e3 100644 --- a/shared/src/i18n/fr/roadtrip.ts +++ b/shared/src/i18n/fr/roadtrip.ts @@ -57,7 +57,9 @@ const roadtrip: TranslationStrings = { 'roadtrip.window.conflict': 'Une heure fixe est incompatible avec le trajet et les pauses. Les heures manuelles sont conservées ; la planification automatique est suspendue.', 'roadtrip.window.tooLong': - 'Ces horaires nécessitent plus de {days} jours supplémentaires. Élargissez la plage horaire quotidienne.', + 'Ces horaires nécessitent plus de {count} jours supplémentaires. Élargissez la plage horaire quotidienne.', + 'roadtrip.window.tooLong.one': + 'Ces horaires nécessitent plus de {count} jour supplémentaire. Élargissez la plage horaire quotidienne.', 'roadtrip.mode.roadtrip': 'Road trip', 'roadtrip.mode.days': 'Jours', 'roadtrip.mode.label': 'Vue du plan', @@ -104,8 +106,10 @@ const roadtrip: TranslationStrings = { 'roadtrip.limit.minutes': 'min', 'roadtrip.limit.off': 'désactivé', 'roadtrip.limit.blockNote': 'Un bloc = {distance}', - 'roadtrip.limit.echoOver': '{over} jours sur {days} dépassent ta limite.', - 'roadtrip.limit.echoNone': 'Les {days} jours respectent tes limites.', + 'roadtrip.limit.echoOver': '{over} jours sur {count} dépassent ta limite.', + 'roadtrip.limit.echoOver.one': '{over} jours sur {count} dépassent ta limite.', + 'roadtrip.limit.echoNone': 'Les {count} jours respectent tes limites.', + 'roadtrip.limit.echoNone.one': '{count} jour, dans tes limites.', 'roadtrip.limit.echoDry': '{count} tronçons sans arrêt accessible.', 'roadtrip.limit.echoDry.one': '{count} tronçon sans arrêt accessible.', 'roadtrip.limit.echoEmpty': 'Ouvre un road trip pour voir l’effet.', @@ -275,8 +279,10 @@ const roadtrip: TranslationStrings = { 'roadtrip.stop.computed': 'Calculé d’après le trajet', 'roadtrip.stop.endIsLeave': 'Pendant le road trip, le départ se fait à cette heure.', 'roadtrip.via.hint': 'Faites glisser pour remodeler l’itinéraire, clic droit pour supprimer', - 'roadtrip.warn.late': 'Arrivée {minutes} min après l’heure fixée', - 'roadtrip.warn.missedLeave': 'Arrivée {minutes} min après l’heure de départ fixée', + 'roadtrip.warn.late': 'Arrivée {count} min après l’heure fixée', + 'roadtrip.warn.late.one': 'Arrivée {count} min après l’heure fixée', + 'roadtrip.warn.missedLeave': 'Arrivée {count} min après l’heure de départ fixée', + 'roadtrip.warn.missedLeave.one': 'Arrivée {count} min après l’heure de départ fixée', 'roadtrip.warn.overnight': 'Jour suivant', 'roadtrip.spill.title': 'Du jour {number}', 'roadtrip.spill.departs': 'départ {time}', diff --git a/shared/src/i18n/fr/settings.ts b/shared/src/i18n/fr/settings.ts index 53061a0b9..3be380750 100644 --- a/shared/src/i18n/fr/settings.ts +++ b/shared/src/i18n/fr/settings.ts @@ -644,7 +644,9 @@ const settings: TranslationStrings = { 'settings.apiKeys.neverUsed': 'jamais utilisée', 'settings.apiKeys.loadFailed': 'Impossible de charger vos clés. Rechargez la page pour réessayer.', 'settings.apiKeys.limitReached': - "Vous avez {max} clés, le maximum pour un compte. Supprimez-en une dont vous n'avez plus besoin pour en créer une autre.", + "Vous avez {count} clés, le maximum pour un compte. Supprimez-en une dont vous n'avez plus besoin pour en créer une autre.", + 'settings.apiKeys.limitReached.one': + "Vous avez {count} clé, le maximum pour un compte. Supprimez-la si vous n'en avez plus besoin pour en créer une autre.", 'settings.apiKeys.copyFailed': 'Impossible de copier. Sélectionnez le texte et copiez-le manuellement.', 'settings.apiKeys.modal.createTitle': 'Créer une clé API', 'settings.apiKeys.modal.name': 'Nom', diff --git a/shared/src/i18n/fr/storage.ts b/shared/src/i18n/fr/storage.ts index 2532e4f33..6dcd95135 100644 --- a/shared/src/i18n/fr/storage.ts +++ b/shared/src/i18n/fr/storage.ts @@ -126,7 +126,8 @@ const storage: TranslationStrings = { // Category migration (copy → flip → delta sweep) 'storage.migrate.promptTitle': 'Déplacer les objets existants vers le nouveau backend ?', - 'storage.migrate.promptLine': '{category} : {objects} objets ({size}) de {from} vers {to}', + 'storage.migrate.promptLine': '{category} : {count} objets ({size}) de {from} vers {to}', + 'storage.migrate.promptLine.one': '{category} : {count} objet ({size}) de {from} vers {to}', 'storage.migrate.promptLineUnknown': '{category} : taille inconnue (utilisation pas encore calculée) de {from} vers {to}', 'storage.migrate.move': 'Déplacer les objets existants', @@ -136,7 +137,8 @@ const storage: TranslationStrings = { 'storage.migrate.doneFailures': "{failed} en échec — ces objets n'ont pas été copiés vers le nouveau backend", 'storage.migrate.failed': "Échec du déplacement : {error} — la catégorie n'a pas été changée", 'storage.migrate.cancelled': "Déplacement annulé — rien n'a été changé", - 'storage.migrate.reclaimable': '{objects} objets ({size}) restent sur {from} — à récupérer manuellement', + 'storage.migrate.reclaimable': '{count} objets ({size}) restent sur {from}, à récupérer manuellement', + 'storage.migrate.reclaimable.one': '{count} objet ({size}) reste sur {from}, à récupérer manuellement', 'storage.migrate.cancel': 'Annuler le déplacement', 'storage.migrate.promptCancel': 'Annuler', 'storage.migrate.queued': "En file d'attente : {categories}", diff --git a/shared/src/i18n/gr/collab.ts b/shared/src/i18n/gr/collab.ts index 8884f46ca..9e75a5916 100644 --- a/shared/src/i18n/gr/collab.ts +++ b/shared/src/i18n/gr/collab.ts @@ -100,7 +100,8 @@ const collab: TranslationStrings = { 'collab.polls.options': 'Επιλογές', 'collab.polls.delete': 'Διαγραφή', 'collab.polls.closedSection': 'Κλειστές', - 'collab.chat.imageLimit': 'Μπορείτε να επισυνάψετε έως {max} εικόνες ανά μήνυμα', + 'collab.chat.imageLimit': 'Μπορείτε να επισυνάψετε έως {count} εικόνες ανά μήνυμα', + 'collab.chat.imageLimit.one': 'Μπορείτε να επισυνάψετε μόνο {count} εικόνα ανά μήνυμα', 'collab.chat.uploading': 'Μεταφόρτωση {percent}%', 'collab.chat.attachImages': 'Επισύναψη εικόνων', 'collab.chat.attachedImage': 'Συνημμένη εικόνα', diff --git a/shared/src/i18n/gr/dashboard.ts b/shared/src/i18n/gr/dashboard.ts index 74cc3ef82..761286762 100644 --- a/shared/src/i18n/gr/dashboard.ts +++ b/shared/src/i18n/gr/dashboard.ts @@ -111,7 +111,8 @@ const dashboard: TranslationStrings = { 'dashboard.useUnsplashPhoto': 'Χρήση φωτογραφίας Unsplash από {photographer}', 'dashboard.titleRequired': 'Ο τίτλος είναι υποχρεωτικός', 'dashboard.endDateError': 'Η ημερομηνία λήξης πρέπει να είναι μετά την ημερομηνία έναρξης', - 'dashboard.tripTooLong': 'Ένα ταξίδι μπορεί να διαρκεί το πολύ {days} ημέρες', + 'dashboard.tripTooLong': 'Ένα ταξίδι μπορεί να διαρκεί το πολύ {count} ημέρες', + 'dashboard.tripTooLong.one': 'Ένα ταξίδι μπορεί να διαρκεί το πολύ {count} ημέρα', 'dashboard.dateShiftTitle': 'Νέα ημερομηνία έναρξης', 'dashboard.dateShiftIntro': 'Αλλάξατε την ημερομηνία έναρξης αυτού του ταξιδιού. Πώς θέλετε να ακολουθήσουν τα σχέδιά σας τις νέες ημερομηνίες;', diff --git a/shared/src/i18n/gr/dawarich.ts b/shared/src/i18n/gr/dawarich.ts index c040cf882..353ae8be5 100644 --- a/shared/src/i18n/gr/dawarich.ts +++ b/shared/src/i18n/gr/dawarich.ts @@ -120,7 +120,8 @@ const dawarich: TranslationStrings = { 'dawarich.accept.confirm.journal': 'Προσθήκη καταχώρησης', 'dawarich.accept.confirm.bucket_list': 'Σημείωση ως εκπληρωμένης', 'dawarich.accept.recorded': 'Καταγράφηκε από {from} έως {to}', - 'dawarich.accept.duration': '{minutes} λεπτά', + 'dawarich.accept.duration': '{count} λεπτά', + 'dawarich.accept.duration.one': '{count} λεπτό', 'dawarich.accept.name': 'Όνομα', 'dawarich.accept.date': 'Ημερομηνία', 'dawarich.accept.from': 'Άφιξη', @@ -186,7 +187,10 @@ const dawarich: TranslationStrings = { 'dawarich.again': 'Έλεγχος ξανά', 'dawarich.bucket.metersAway': '{meters} μ. μακριά', 'dawarich.bucket.kilometersAway': '{km} χλμ. μακριά', - 'dawarich.bucket.rule': 'Μια επιθυμία μετράει ως εκπληρωμένη σε απόσταση έως {meters} μ. και μετά από {minutes} λεπτά στο σημείο.', + 'dawarich.bucket.rule': + 'Μια επιθυμία μετράει ως εκπληρωμένη σε απόσταση έως {meters} μ. και μετά από {count} λεπτά στο σημείο.', + 'dawarich.bucket.rule.one': + 'Μια επιθυμία μετράει ως εκπληρωμένη σε απόσταση έως {meters} μ. και μετά από {count} λεπτό στο σημείο.', 'dawarich.journey.dayStays.other': '{count} στάσεις από το Dawarich', 'dawarich.journey.dayStays.one': '1 στάση από το Dawarich', diff --git a/shared/src/i18n/gr/roadtrip.ts b/shared/src/i18n/gr/roadtrip.ts index c9e7ecb1d..011bdc668 100644 --- a/shared/src/i18n/gr/roadtrip.ts +++ b/shared/src/i18n/gr/roadtrip.ts @@ -58,7 +58,9 @@ const roadtrip: TranslationStrings = { 'roadtrip.window.conflict': 'Μια σταθερή ώρα συγκρούεται με την οδήγηση και τις παύσεις. Οι χειροκίνητες ώρες διατηρούνται· ο αυτόματος σχεδιασμός έχει παύσει.', 'roadtrip.window.tooLong': - 'Αυτές οι ώρες απαιτούν πάνω από {days} επιπλέον ημέρες. Επιλέξτε μεγαλύτερο ημερήσιο διάστημα.', + 'Αυτές οι ώρες απαιτούν πάνω από {count} επιπλέον ημέρες. Επιλέξτε μεγαλύτερο ημερήσιο διάστημα.', + 'roadtrip.window.tooLong.one': + 'Αυτές οι ώρες απαιτούν πάνω από {count} επιπλέον ημέρα. Επιλέξτε μεγαλύτερο ημερήσιο διάστημα.', 'roadtrip.mode.roadtrip': 'Οδικό ταξίδι', 'roadtrip.mode.days': 'Ημέρες', 'roadtrip.mode.label': 'Προβολή σχεδίου', @@ -105,8 +107,10 @@ const roadtrip: TranslationStrings = { 'roadtrip.limit.minutes': 'λεπ', 'roadtrip.limit.off': 'ανενεργό', 'roadtrip.limit.blockNote': 'Ένα μπλοκ = {distance}', - 'roadtrip.limit.echoOver': '{over} από {days} ημέρες πάνω από το όριο.', - 'roadtrip.limit.echoNone': 'Και οι {days} ημέρες εντός ορίων.', + 'roadtrip.limit.echoOver': '{over} από {count} ημέρες πάνω από το όριο.', + 'roadtrip.limit.echoOver.one': '{over} από {count} ημέρα πάνω από το όριο.', + 'roadtrip.limit.echoNone': 'Και οι {count} ημέρες εντός ορίων.', + 'roadtrip.limit.echoNone.one': 'Η μία ημέρα είναι εντός ορίων.', 'roadtrip.limit.echoDry': '{count} τμήματα χωρίς στάση εντός αυτονομίας.', 'roadtrip.limit.echoDry.one': '{count} τμήμα χωρίς στάση εντός αυτονομίας.', 'roadtrip.limit.echoEmpty': 'Άνοιξε ένα ταξίδι για να δεις το αποτέλεσμα.', @@ -277,8 +281,10 @@ const roadtrip: TranslationStrings = { 'roadtrip.stop.computed': 'Υπολογισμένη από τη διαδρομή', 'roadtrip.stop.endIsLeave': 'Στο οδικό ταξίδι, η αναχώρηση γίνεται αυτή την ώρα.', 'roadtrip.via.hint': 'Σύρετε για να αλλάξετε τη διαδρομή, δεξί κλικ για αφαίρεση', - 'roadtrip.warn.late': 'Άφιξη {minutes} λεπτά μετά την ορισμένη ώρα', - 'roadtrip.warn.missedLeave': 'Άφιξη {minutes} λεπτά μετά την ορισμένη ώρα αναχώρησης', + 'roadtrip.warn.late': 'Άφιξη {count} λεπτά μετά την ορισμένη ώρα', + 'roadtrip.warn.late.one': 'Άφιξη {count} λεπτό μετά την ορισμένη ώρα', + 'roadtrip.warn.missedLeave': 'Άφιξη {count} λεπτά μετά την ορισμένη ώρα αναχώρησης', + 'roadtrip.warn.missedLeave.one': 'Άφιξη {count} λεπτό μετά την ορισμένη ώρα αναχώρησης', 'roadtrip.warn.overnight': 'Επόμενη μέρα', 'roadtrip.spill.title': 'Από την ημέρα {number}', 'roadtrip.spill.departs': 'αναχώρηση {time}', diff --git a/shared/src/i18n/gr/settings.ts b/shared/src/i18n/gr/settings.ts index 75d6746df..d28f824b0 100644 --- a/shared/src/i18n/gr/settings.ts +++ b/shared/src/i18n/gr/settings.ts @@ -642,7 +642,10 @@ const settings: TranslationStrings = { 'settings.apiKeys.endpoint': 'Endpoint', 'settings.apiKeys.neverUsed': 'δεν χρησιμοποιήθηκε ποτέ', 'settings.apiKeys.loadFailed': 'Δεν ήταν δυνατή η φόρτωση των κλειδιών σου. Φόρτωσε ξανά τη σελίδα για να δοκιμάσεις πάλι.', - 'settings.apiKeys.limitReached': 'Έχεις {max} κλειδιά, το μέγιστο για έναν λογαριασμό. Διάγραψε ένα που δεν χρησιμοποιείς πια για να δημιουργήσεις νέο.', + 'settings.apiKeys.limitReached': + 'Έχεις {count} κλειδιά, το μέγιστο για έναν λογαριασμό. Διάγραψε ένα που δεν χρησιμοποιείς πια για να δημιουργήσεις νέο.', + 'settings.apiKeys.limitReached.one': + 'Έχεις {count} κλειδί, το μέγιστο για έναν λογαριασμό. Διάγραψέ το αν δεν το χρησιμοποιείς πια για να δημιουργήσεις νέο.', 'settings.apiKeys.copyFailed': 'Η αντιγραφή απέτυχε. Επίλεξε το κείμενο και αντίγραψέ το χειροκίνητα.', 'settings.apiKeys.modal.createTitle': 'Δημιουργία κλειδιού API', 'settings.apiKeys.modal.name': 'Όνομα', diff --git a/shared/src/i18n/gr/storage.ts b/shared/src/i18n/gr/storage.ts index 96306858a..2d57a6e85 100644 --- a/shared/src/i18n/gr/storage.ts +++ b/shared/src/i18n/gr/storage.ts @@ -127,7 +127,8 @@ const storage: TranslationStrings = { // Category migration (copy → flip → delta sweep) 'storage.migrate.promptTitle': 'Μετακίνηση των υπαρχόντων αντικειμένων στο νέο backend;', - 'storage.migrate.promptLine': '{category}: {objects} αντικείμενα ({size}) από {from} σε {to}', + 'storage.migrate.promptLine': '{category}: {count} αντικείμενα ({size}) από {from} σε {to}', + 'storage.migrate.promptLine.one': '{category}: {count} αντικείμενο ({size}) από {from} σε {to}', 'storage.migrate.promptLineUnknown': '{category}: άγνωστο μέγεθος (δεν έχει γίνει ακόμα σάρωση χρήσης) από {from} σε {to}', 'storage.migrate.move': 'Μετακίνηση υπαρχόντων αντικειμένων', @@ -137,7 +138,8 @@ const storage: TranslationStrings = { 'storage.migrate.doneFailures': '{failed} απέτυχαν — αυτά τα αντικείμενα δεν αντιγράφηκαν στο νέο backend', 'storage.migrate.failed': 'Η μετακίνηση απέτυχε: {error} — η κατηγορία δεν άλλαξε', 'storage.migrate.cancelled': 'Η μετακίνηση ακυρώθηκε — τίποτα δεν άλλαξε', - 'storage.migrate.reclaimable': '{objects} αντικείμενα ({size}) παραμένουν στο {from} — ανάκτησέ τα χειροκίνητα', + 'storage.migrate.reclaimable': '{count} αντικείμενα ({size}) παραμένουν στο {from}, ανάκτησέ τα χειροκίνητα', + 'storage.migrate.reclaimable.one': '{count} αντικείμενο ({size}) παραμένει στο {from}, ανάκτησέ το χειροκίνητα', 'storage.migrate.cancel': 'Ακύρωση μετακίνησης', 'storage.migrate.promptCancel': 'Ακύρωση', 'storage.migrate.queued': 'Σε αναμονή: {categories}', diff --git a/shared/src/i18n/hu/collab.ts b/shared/src/i18n/hu/collab.ts index 7271d8ae1..806f9dd30 100644 --- a/shared/src/i18n/hu/collab.ts +++ b/shared/src/i18n/hu/collab.ts @@ -100,7 +100,8 @@ const collab: TranslationStrings = { 'collab.polls.options': 'Opciók', 'collab.polls.delete': 'Törlés', 'collab.polls.closedSection': 'Lezárva', - 'collab.chat.imageLimit': 'Üzenetenként legfeljebb {max} képet csatolhatsz', + 'collab.chat.imageLimit': 'Üzenetenként legfeljebb {count} képet csatolhatsz', + 'collab.chat.imageLimit.one': 'Üzenetenként csak {count} képet csatolhatsz', 'collab.chat.uploading': 'Feltöltés {percent}%', 'collab.chat.attachImages': 'Képek csatolása', 'collab.chat.attachedImage': 'Csatolt kép', diff --git a/shared/src/i18n/hu/dashboard.ts b/shared/src/i18n/hu/dashboard.ts index 0f6ae2495..52b8ae1ab 100644 --- a/shared/src/i18n/hu/dashboard.ts +++ b/shared/src/i18n/hu/dashboard.ts @@ -101,7 +101,8 @@ const dashboard: TranslationStrings = { 'dashboard.useUnsplashPhoto': '{photographer} Unsplash-fotójának használata', 'dashboard.titleRequired': 'A cím megadása kötelező', 'dashboard.endDateError': 'A záró dátumnak a kezdő dátum után kell lennie', - 'dashboard.tripTooLong': 'Egy utazás legfeljebb {days} napos lehet', + 'dashboard.tripTooLong': 'Egy utazás legfeljebb {count} napos lehet', + 'dashboard.tripTooLong.one': 'Egy utazás legfeljebb {count} napos lehet', 'dashboard.dateShiftTitle': 'Új kezdő dátum', 'dashboard.dateShiftIntro': 'Megváltoztattad az út kezdetét. Hogyan kövessék a terveid az új dátumokat?', 'dashboard.dateShiftKeepBookings': 'A foglalások maradjanak a saját dátumaikon', diff --git a/shared/src/i18n/hu/dawarich.ts b/shared/src/i18n/hu/dawarich.ts index 8a8ecd018..f81a43595 100644 --- a/shared/src/i18n/hu/dawarich.ts +++ b/shared/src/i18n/hu/dawarich.ts @@ -119,7 +119,8 @@ const dawarich: TranslationStrings = { 'dawarich.accept.confirm.journal': 'Bejegyzés hozzáadása', 'dawarich.accept.confirm.bucket_list': 'Pipáld ki', 'dawarich.accept.recorded': 'Rögzítve {from} és {to} között', - 'dawarich.accept.duration': '{minutes} perc', + 'dawarich.accept.duration': '{count} perc', + 'dawarich.accept.duration.one': '{count} perc', 'dawarich.accept.name': 'Név', 'dawarich.accept.date': 'Dátum', 'dawarich.accept.from': 'Érkezés', @@ -184,7 +185,10 @@ const dawarich: TranslationStrings = { 'dawarich.again': 'Ellenőrzés újra', 'dawarich.bucket.metersAway': '{meters} m-re', 'dawarich.bucket.kilometersAway': '{km} km-re', - 'dawarich.bucket.rule': 'Egy kívánság {meters} méteren belül és {minutes} perc helyszíni idő után számít teljesítettnek.', + 'dawarich.bucket.rule': + 'Egy kívánság {meters} méteren belül és {count} perc helyszíni idő után számít teljesítettnek.', + 'dawarich.bucket.rule.one': + 'Egy kívánság {meters} méteren belül és {count} perc helyszíni idő után számít teljesítettnek.', 'dawarich.journey.dayStays.other': '{count} tartózkodás a Dawarichból', 'dawarich.journey.dayStays.one': '{count} tartózkodás a Dawarichból', diff --git a/shared/src/i18n/hu/roadtrip.ts b/shared/src/i18n/hu/roadtrip.ts index 9e4c09fbb..136921ec3 100644 --- a/shared/src/i18n/hu/roadtrip.ts +++ b/shared/src/i18n/hu/roadtrip.ts @@ -56,7 +56,9 @@ const roadtrip: TranslationStrings = { 'roadtrip.window.conflict': 'Egy rögzített időpont ütközik az utazással és a szünetekkel. A kézi időpontok megmaradnak; az automatikus tervezés szünetel.', 'roadtrip.window.tooLong': - 'Ezek az időpontok több mint {days} további napot igényelnének. Válassz hosszabb napi időszakot.', + 'Ezek az időpontok több mint {count} további napot igényelnének. Válassz hosszabb napi időszakot.', + 'roadtrip.window.tooLong.one': + 'Ezek az időpontok több mint {count} további napot igényelnének. Válassz hosszabb napi időszakot.', 'roadtrip.mode.roadtrip': 'Autós út', 'roadtrip.mode.days': 'Napok', 'roadtrip.mode.label': 'Terv nézet', @@ -103,8 +105,10 @@ const roadtrip: TranslationStrings = { 'roadtrip.limit.minutes': 'perc', 'roadtrip.limit.off': 'ki', 'roadtrip.limit.blockNote': 'Egy blokk = {distance}', - 'roadtrip.limit.echoOver': '{days} napból {over} a határ felett.', - 'roadtrip.limit.echoNone': 'Mind a(z) {days} nap a határokon belül.', + 'roadtrip.limit.echoOver': '{count} napból {over} a határ felett.', + 'roadtrip.limit.echoOver.one': '{count} napból {over} a határ felett.', + 'roadtrip.limit.echoNone': 'Mind a(z) {count} nap a határokon belül.', + 'roadtrip.limit.echoNone.one': 'Az egyetlen nap a határokon belül.', 'roadtrip.limit.echoDry': '{count} szakasz elérhető megálló nélkül.', 'roadtrip.limit.echoDry.one': '{count} szakasz elérhető megálló nélkül.', 'roadtrip.limit.echoEmpty': 'Nyiss meg egy utat, hogy lásd a hatást.', @@ -274,8 +278,10 @@ const roadtrip: TranslationStrings = { 'roadtrip.stop.computed': 'A menetidőből számolva', 'roadtrip.stop.endIsLeave': 'Az autós úton ekkor indul tovább az út.', 'roadtrip.via.hint': 'Húzza az útvonal átalakításához, jobb gombbal eltávolítható', - 'roadtrip.warn.late': 'Érkezés {minutes} perccel a megadott idő után', - 'roadtrip.warn.missedLeave': 'Érkezés {minutes} perccel a megadott indulási idő után', + 'roadtrip.warn.late': 'Érkezés {count} perccel a megadott idő után', + 'roadtrip.warn.late.one': 'Érkezés {count} perccel a megadott idő után', + 'roadtrip.warn.missedLeave': 'Érkezés {count} perccel a megadott indulási idő után', + 'roadtrip.warn.missedLeave.one': 'Érkezés {count} perccel a megadott indulási idő után', 'roadtrip.warn.overnight': 'Következő nap', 'roadtrip.spill.title': 'A(z) {number}. napról', 'roadtrip.spill.departs': 'indulás {time}', diff --git a/shared/src/i18n/hu/settings.ts b/shared/src/i18n/hu/settings.ts index 7fe142a07..5ed0260b9 100644 --- a/shared/src/i18n/hu/settings.ts +++ b/shared/src/i18n/hu/settings.ts @@ -631,7 +631,10 @@ const settings: TranslationStrings = { 'settings.apiKeys.endpoint': 'Végpont', 'settings.apiKeys.neverUsed': 'még nem használt', 'settings.apiKeys.loadFailed': 'Nem sikerült betölteni a kulcsaidat. Töltsd újra az oldalt, és próbáld újra.', - 'settings.apiKeys.limitReached': '{max} kulcsod van, ennél több egy fiókhoz nem tartozhat. Törölj egy már nem használt kulcsot, hogy újat hozhass létre.', + 'settings.apiKeys.limitReached': + '{count} kulcsod van, ennél több egy fiókhoz nem tartozhat. Törölj egy már nem használt kulcsot, hogy újat hozhass létre.', + 'settings.apiKeys.limitReached.one': + '{count} kulcsod van, ennél több egy fiókhoz nem tartozhat. Töröld, ha már nem használod, hogy újat hozhass létre.', 'settings.apiKeys.copyFailed': 'A másolás nem sikerült. Jelöld ki a szöveget, és másold ki kézzel.', 'settings.apiKeys.modal.createTitle': 'API-kulcs létrehozása', 'settings.apiKeys.modal.name': 'Név', diff --git a/shared/src/i18n/hu/storage.ts b/shared/src/i18n/hu/storage.ts index 072d71d0a..399550671 100644 --- a/shared/src/i18n/hu/storage.ts +++ b/shared/src/i18n/hu/storage.ts @@ -125,7 +125,8 @@ const storage: TranslationStrings = { // Category migration (copy → flip → delta sweep) 'storage.migrate.promptTitle': 'Áthelyezed a meglévő objektumokat az új backendre?', - 'storage.migrate.promptLine': '{category}: {objects} objektum ({size}) innen: {from} ide: {to}', + 'storage.migrate.promptLine': '{category}: {count} objektum ({size}) innen: {from} ide: {to}', + 'storage.migrate.promptLine.one': '{category}: {count} objektum ({size}) innen: {from} ide: {to}', 'storage.migrate.promptLineUnknown': '{category}: ismeretlen méret (a használat még nincs kiszámítva) innen: {from} ide: {to}', 'storage.migrate.move': 'Meglévő objektumok áthelyezése', @@ -135,7 +136,8 @@ const storage: TranslationStrings = { 'storage.migrate.doneFailures': '{failed} sikertelen — ezek az objektumok nem lettek átmásolva az új backendre', 'storage.migrate.failed': 'Az áthelyezés sikertelen: {error} — a kategória nem lett átváltva', 'storage.migrate.cancelled': 'Áthelyezés megszakítva — semmi sem lett átváltva', - 'storage.migrate.reclaimable': '{objects} objektum ({size}) marad a(z) {from} helyen — kézzel szabadítsd fel', + 'storage.migrate.reclaimable': '{count} objektum ({size}) marad a(z) {from} helyen, kézzel szabadítsd fel', + 'storage.migrate.reclaimable.one': '{count} objektum ({size}) marad a(z) {from} helyen, kézzel szabadítsd fel', 'storage.migrate.cancel': 'Áthelyezés megszakítása', 'storage.migrate.promptCancel': 'Mégse', 'storage.migrate.queued': 'Várólistán: {categories}', diff --git a/shared/src/i18n/i18n-parity.spec.ts b/shared/src/i18n/i18n-parity.spec.ts index 20f48eea6..f11097f9b 100644 --- a/shared/src/i18n/i18n-parity.spec.ts +++ b/shared/src/i18n/i18n-parity.spec.ts @@ -35,11 +35,13 @@ describe('i18n parity', () => { describe('i18n count strings', () => { const ROOT = new URL('../../scripts/fixtures/i18n/', import.meta.url); - it('refuses an en string with {count} or {n} outside a plural group', () => { + it('refuses an en string with {count}, {n} or a quantity param outside a plural group', () => { const { ungrouped, stale } = checkCountStrings(['a.ts'], [], ROOT); + // a.stay carries its quantity as {days}, which no plural form is picked by. expect(ungrouped).toEqual([ { file: 'a.ts', key: 'a.lone' }, { file: 'a.ts', key: 'a.day' }, + { file: 'a.ts', key: 'a.stay' }, ]); expect(stale).toEqual([]); }); @@ -50,7 +52,10 @@ describe('i18n count strings', () => { { key: 'a.count', because: 'a group now' }, ]; expect(checkCountStrings(['a.ts'], allowed, ROOT)).toEqual({ - ungrouped: [{ file: 'a.ts', key: 'a.lone' }], + ungrouped: [ + { file: 'a.ts', key: 'a.lone' }, + { file: 'a.ts', key: 'a.stay' }, + ], stale: ['a.count'], }); }); diff --git a/shared/src/i18n/id/collab.ts b/shared/src/i18n/id/collab.ts index 5eba1191f..811e923a6 100644 --- a/shared/src/i18n/id/collab.ts +++ b/shared/src/i18n/id/collab.ts @@ -96,7 +96,7 @@ const collab: TranslationStrings = { 'collab.polls.options': 'Pilihan', 'collab.polls.delete': 'Hapus', 'collab.polls.closedSection': 'Ditutup', - 'collab.chat.imageLimit': 'Anda dapat melampirkan hingga {max} gambar per pesan', + 'collab.chat.imageLimit': 'Anda dapat melampirkan hingga {count} gambar per pesan', 'collab.chat.uploading': 'Mengunggah {percent}%', 'collab.chat.attachImages': 'Lampirkan gambar', 'collab.chat.attachedImage': 'Gambar terlampir', diff --git a/shared/src/i18n/id/dashboard.ts b/shared/src/i18n/id/dashboard.ts index 55b0205a9..b12dcdcc3 100644 --- a/shared/src/i18n/id/dashboard.ts +++ b/shared/src/i18n/id/dashboard.ts @@ -92,7 +92,7 @@ const dashboard: TranslationStrings = { 'dashboard.useUnsplashPhoto': 'Gunakan foto Unsplash oleh {photographer}', 'dashboard.titleRequired': 'Judul wajib diisi', 'dashboard.endDateError': 'Tanggal selesai harus setelah tanggal mulai', - 'dashboard.tripTooLong': 'Perjalanan paling lama {days} hari', + 'dashboard.tripTooLong': 'Perjalanan paling lama {count} hari', 'dashboard.dateShiftTitle': 'Tanggal mulai baru', 'dashboard.dateShiftIntro': 'Kamu mengubah tanggal mulai perjalanan ini. Bagaimana rencanamu harus mengikuti tanggal baru?', diff --git a/shared/src/i18n/id/dawarich.ts b/shared/src/i18n/id/dawarich.ts index 458f8404f..ddc825fd6 100644 --- a/shared/src/i18n/id/dawarich.ts +++ b/shared/src/i18n/id/dawarich.ts @@ -114,7 +114,7 @@ const dawarich: TranslationStrings = { 'dawarich.accept.confirm.journal': 'Tambah entri', 'dawarich.accept.confirm.bucket_list': 'Coret', 'dawarich.accept.recorded': 'Terekam {from} sampai {to}', - 'dawarich.accept.duration': '{minutes} mnt', + 'dawarich.accept.duration': '{count} mnt', 'dawarich.accept.name': 'Nama', 'dawarich.accept.date': 'Tanggal', 'dawarich.accept.from': 'Tiba', @@ -172,7 +172,8 @@ const dawarich: TranslationStrings = { 'dawarich.again': 'Periksa lagi', 'dawarich.bucket.metersAway': '{meters} m dari sana', 'dawarich.bucket.kilometersAway': '{km} km dari sana', - 'dawarich.bucket.rule': 'Sebuah keinginan dianggap tercapai dalam radius {meters} m dan setelah {minutes} menit di lokasi.', + 'dawarich.bucket.rule': + 'Sebuah keinginan dianggap tercapai dalam radius {meters} m dan setelah {count} menit di lokasi.', 'dawarich.journey.dayStays.other': '{count} persinggahan dari Dawarich', }; diff --git a/shared/src/i18n/id/roadtrip.ts b/shared/src/i18n/id/roadtrip.ts index 9d174333d..1afe87591 100644 --- a/shared/src/i18n/id/roadtrip.ts +++ b/shared/src/i18n/id/roadtrip.ts @@ -56,7 +56,7 @@ const roadtrip: TranslationStrings = { 'roadtrip.window.conflict': 'Waktu tetap bertentangan dengan perjalanan dan jeda. Waktu manual tidak berubah; perencanaan otomatis dijeda.', 'roadtrip.window.tooLong': - 'Waktu ini memerlukan lebih dari {days} hari tambahan. Pilih rentang waktu harian yang lebih panjang.', + 'Waktu ini memerlukan lebih dari {count} hari tambahan. Pilih rentang waktu harian yang lebih panjang.', 'roadtrip.mode.roadtrip': 'Perjalanan darat', 'roadtrip.mode.days': 'Hari', 'roadtrip.mode.label': 'Tampilan rencana', @@ -102,8 +102,8 @@ const roadtrip: TranslationStrings = { 'roadtrip.limit.minutes': 'mnt', 'roadtrip.limit.off': 'mati', 'roadtrip.limit.blockNote': 'Satu blok = {distance}', - 'roadtrip.limit.echoOver': '{over} dari {days} hari melebihi batasmu.', - 'roadtrip.limit.echoNone': 'Semua {days} hari dalam batasmu.', + 'roadtrip.limit.echoOver': '{over} dari {count} hari melebihi batasmu.', + 'roadtrip.limit.echoNone': 'Semua {count} hari dalam batasmu.', 'roadtrip.limit.echoDry': '{count} ruas tanpa perhentian terjangkau.', 'roadtrip.limit.echoEmpty': 'Buka sebuah road trip untuk melihat efeknya.', 'roadtrip.limit.specToggle': 'Hitung dari data mobil', @@ -262,8 +262,8 @@ const roadtrip: TranslationStrings = { 'roadtrip.stop.computed': 'Dihitung dari waktu berkendara', 'roadtrip.stop.endIsLeave': 'Dalam perjalanan darat, keberangkatan pada waktu ini.', 'roadtrip.via.hint': 'Seret untuk mengubah rute, klik kanan untuk menghapus', - 'roadtrip.warn.late': 'Tiba {minutes} menit setelah waktu yang ditetapkan', - 'roadtrip.warn.missedLeave': 'Tiba {minutes} menit setelah waktu berangkat yang ditetapkan', + 'roadtrip.warn.late': 'Tiba {count} menit setelah waktu yang ditetapkan', + 'roadtrip.warn.missedLeave': 'Tiba {count} menit setelah waktu berangkat yang ditetapkan', 'roadtrip.warn.overnight': 'Hari berikutnya', 'roadtrip.spill.title': 'Dari hari {number}', 'roadtrip.spill.departs': 'berangkat {time}', diff --git a/shared/src/i18n/id/settings.ts b/shared/src/i18n/id/settings.ts index 3c9b6da68..387dcc526 100644 --- a/shared/src/i18n/id/settings.ts +++ b/shared/src/i18n/id/settings.ts @@ -621,7 +621,8 @@ const settings: TranslationStrings = { 'settings.apiKeys.endpoint': 'Endpoint', 'settings.apiKeys.neverUsed': 'belum pernah dipakai', 'settings.apiKeys.loadFailed': 'Kunci tidak dapat dimuat. Muat ulang halaman untuk mencoba lagi.', - 'settings.apiKeys.limitReached': 'Kamu punya {max} kunci, batas maksimum per akun. Hapus kunci yang tidak lagi dipakai untuk membuat yang baru.', + 'settings.apiKeys.limitReached': + 'Kamu punya {count} kunci, batas maksimum per akun. Hapus kunci yang tidak lagi dipakai untuk membuat yang baru.', 'settings.apiKeys.copyFailed': 'Gagal menyalin. Pilih teksnya dan salin secara manual.', 'settings.apiKeys.modal.createTitle': 'Buat kunci API', 'settings.apiKeys.modal.name': 'Nama', diff --git a/shared/src/i18n/id/storage.ts b/shared/src/i18n/id/storage.ts index c05f702b3..d86ec9a8d 100644 --- a/shared/src/i18n/id/storage.ts +++ b/shared/src/i18n/id/storage.ts @@ -122,7 +122,7 @@ const storage: TranslationStrings = { // Category migration (copy → flip → delta sweep) 'storage.migrate.promptTitle': 'Pindahkan objek yang ada ke backend baru?', - 'storage.migrate.promptLine': '{category}: {objects} objek ({size}) dari {from} ke {to}', + 'storage.migrate.promptLine': '{category}: {count} objek ({size}) dari {from} ke {to}', 'storage.migrate.promptLineUnknown': '{category}: ukuran tidak diketahui (penggunaan belum dipindai) dari {from} ke {to}', 'storage.migrate.move': 'Pindahkan objek yang ada', @@ -132,7 +132,7 @@ const storage: TranslationStrings = { 'storage.migrate.doneFailures': '{failed} gagal — objek tersebut tidak disalin ke backend baru', 'storage.migrate.failed': 'Pemindahan gagal: {error} — kategori tidak diubah', 'storage.migrate.cancelled': 'Pemindahan dibatalkan — tidak ada yang diubah', - 'storage.migrate.reclaimable': '{objects} objek ({size}) masih tersisa di {from} — ambil kembali secara manual', + 'storage.migrate.reclaimable': '{count} objek ({size}) masih tersisa di {from}, ambil kembali secara manual', 'storage.migrate.cancel': 'Batalkan pemindahan', 'storage.migrate.promptCancel': 'Batal', 'storage.migrate.queued': 'Dalam antrean: {categories}', diff --git a/shared/src/i18n/it/collab.ts b/shared/src/i18n/it/collab.ts index 33c96d3fe..6ee49c2f1 100644 --- a/shared/src/i18n/it/collab.ts +++ b/shared/src/i18n/it/collab.ts @@ -100,7 +100,8 @@ const collab: TranslationStrings = { 'collab.polls.options': 'Opzioni', 'collab.polls.delete': 'Elimina', 'collab.polls.closedSection': 'Chiusi', - 'collab.chat.imageLimit': 'Puoi allegare fino a {max} immagini per messaggio', + 'collab.chat.imageLimit': 'Puoi allegare fino a {count} immagini per messaggio', + 'collab.chat.imageLimit.one': 'Puoi allegare solo {count} immagine per messaggio', 'collab.chat.uploading': 'Caricamento {percent}%', 'collab.chat.attachImages': 'Allega immagini', 'collab.chat.attachedImage': 'Immagine allegata', diff --git a/shared/src/i18n/it/dashboard.ts b/shared/src/i18n/it/dashboard.ts index 3d2f7c7d7..fb6b9fb24 100644 --- a/shared/src/i18n/it/dashboard.ts +++ b/shared/src/i18n/it/dashboard.ts @@ -101,7 +101,8 @@ const dashboard: TranslationStrings = { 'dashboard.useUnsplashPhoto': 'Usa foto Unsplash di {photographer}', 'dashboard.titleRequired': 'Il titolo è obbligatorio', 'dashboard.endDateError': 'La data di fine deve essere successiva alla data di inizio', - 'dashboard.tripTooLong': 'Un viaggio può durare al massimo {days} giorni', + 'dashboard.tripTooLong': 'Un viaggio può durare al massimo {count} giorni', + 'dashboard.tripTooLong.one': 'Un viaggio può durare al massimo {count} giorno', 'dashboard.dateShiftTitle': 'Nuova data di inizio', 'dashboard.dateShiftIntro': 'Hai modificato la data di inizio di questo viaggio. Come devono adattarsi i tuoi piani alle nuove date?', diff --git a/shared/src/i18n/it/dawarich.ts b/shared/src/i18n/it/dawarich.ts index a7808afc0..2cc7a0e24 100644 --- a/shared/src/i18n/it/dawarich.ts +++ b/shared/src/i18n/it/dawarich.ts @@ -119,7 +119,8 @@ const dawarich: TranslationStrings = { 'dawarich.accept.confirm.journal': 'Aggiungi voce', 'dawarich.accept.confirm.bucket_list': 'Spuntalo', 'dawarich.accept.recorded': 'Registrata dal {from} al {to}', - 'dawarich.accept.duration': '{minutes} min', + 'dawarich.accept.duration': '{count} min', + 'dawarich.accept.duration.one': '{count} min', 'dawarich.accept.name': 'Nome', 'dawarich.accept.date': 'Data', 'dawarich.accept.from': 'Arrivo', @@ -185,7 +186,8 @@ const dawarich: TranslationStrings = { 'dawarich.again': 'Controlla di nuovo', 'dawarich.bucket.metersAway': 'a {meters} m', 'dawarich.bucket.kilometersAway': 'a {km} km', - 'dawarich.bucket.rule': 'Un desiderio è raggiunto entro {meters} m e dopo {minutes} minuti sul posto.', + 'dawarich.bucket.rule': 'Un desiderio è raggiunto entro {meters} m e dopo {count} minuti sul posto.', + 'dawarich.bucket.rule.one': 'Un desiderio è raggiunto entro {meters} m e dopo {count} minuto sul posto.', 'dawarich.journey.dayStays.other': '{count} soste da Dawarich', 'dawarich.journey.dayStays.one': '{count} sosta da Dawarich', diff --git a/shared/src/i18n/it/roadtrip.ts b/shared/src/i18n/it/roadtrip.ts index 0beaae137..0e4e5818d 100644 --- a/shared/src/i18n/it/roadtrip.ts +++ b/shared/src/i18n/it/roadtrip.ts @@ -56,7 +56,9 @@ const roadtrip: TranslationStrings = { 'roadtrip.window.conflict': 'Un orario fisso è incompatibile con il tragitto e le pause. Gli orari manuali restano invariati; la pianificazione automatica è sospesa.', 'roadtrip.window.tooLong': - 'Questi orari richiederebbero oltre {days} giorni aggiuntivi. Scegli un intervallo giornaliero più lungo.', + 'Questi orari richiederebbero oltre {count} giorni aggiuntivi. Scegli un intervallo giornaliero più lungo.', + 'roadtrip.window.tooLong.one': + 'Questi orari richiederebbero oltre {count} giorno aggiuntivo. Scegli un intervallo giornaliero più lungo.', 'roadtrip.mode.roadtrip': 'Viaggio su strada', 'roadtrip.mode.days': 'Giorni', 'roadtrip.mode.label': 'Vista del piano', @@ -103,8 +105,10 @@ const roadtrip: TranslationStrings = { 'roadtrip.limit.minutes': 'min', 'roadtrip.limit.off': 'off', 'roadtrip.limit.blockNote': 'Un blocco = {distance}', - 'roadtrip.limit.echoOver': '{over} giorni su {days} superano il limite.', - 'roadtrip.limit.echoNone': 'Tutti i {days} giorni rientrano nei limiti.', + 'roadtrip.limit.echoOver': '{over} giorni su {count} superano il limite.', + 'roadtrip.limit.echoOver.one': '{over} giorni su {count} superano il limite.', + 'roadtrip.limit.echoNone': 'Tutti i {count} giorni rientrano nei limiti.', + 'roadtrip.limit.echoNone.one': 'L’unico giorno rientra nei limiti.', 'roadtrip.limit.echoDry': '{count} tratti senza sosta raggiungibile.', 'roadtrip.limit.echoDry.one': '{count} tratto senza sosta raggiungibile.', 'roadtrip.limit.echoEmpty': 'Apri un viaggio per vedere l’effetto.', @@ -274,8 +278,10 @@ const roadtrip: TranslationStrings = { 'roadtrip.stop.computed': 'Calcolato dal tragitto', 'roadtrip.stop.endIsLeave': 'Nel viaggio su strada si riparte a quest’ora.', 'roadtrip.via.hint': 'Trascina per rimodellare il percorso, clic destro per rimuovere', - 'roadtrip.warn.late': 'Arrivo {minutes} min dopo l’orario impostato', - 'roadtrip.warn.missedLeave': 'Arrivo {minutes} min dopo l’orario di partenza impostato', + 'roadtrip.warn.late': 'Arrivo {count} min dopo l’orario impostato', + 'roadtrip.warn.late.one': 'Arrivo {count} min dopo l’orario impostato', + 'roadtrip.warn.missedLeave': 'Arrivo {count} min dopo l’orario di partenza impostato', + 'roadtrip.warn.missedLeave.one': 'Arrivo {count} min dopo l’orario di partenza impostato', 'roadtrip.warn.overnight': 'Giorno successivo', 'roadtrip.spill.title': 'Dal giorno {number}', 'roadtrip.spill.departs': 'partenza {time}', diff --git a/shared/src/i18n/it/settings.ts b/shared/src/i18n/it/settings.ts index 12fc435d3..8f28f163e 100644 --- a/shared/src/i18n/it/settings.ts +++ b/shared/src/i18n/it/settings.ts @@ -637,7 +637,9 @@ const settings: TranslationStrings = { 'settings.apiKeys.neverUsed': 'mai usata', 'settings.apiKeys.loadFailed': 'Impossibile caricare le tue chiavi. Ricarica la pagina per riprovare.', 'settings.apiKeys.limitReached': - "Hai {max} chiavi, il massimo per un account. Eliminane una che non usi più per crearne un'altra.", + "Hai {count} chiavi, il massimo per un account. Eliminane una che non usi più per crearne un'altra.", + 'settings.apiKeys.limitReached.one': + "Hai {count} chiave, il massimo per un account. Eliminala se non la usi più per crearne un'altra.", 'settings.apiKeys.copyFailed': 'Impossibile copiare. Seleziona il testo e copialo a mano.', 'settings.apiKeys.modal.createTitle': 'Crea chiave API', 'settings.apiKeys.modal.name': 'Nome', diff --git a/shared/src/i18n/it/storage.ts b/shared/src/i18n/it/storage.ts index d8275b142..521e21972 100644 --- a/shared/src/i18n/it/storage.ts +++ b/shared/src/i18n/it/storage.ts @@ -125,7 +125,8 @@ const storage: TranslationStrings = { // Category migration (copy → flip → delta sweep) 'storage.migrate.promptTitle': 'Spostare gli oggetti esistenti nel nuovo backend?', - 'storage.migrate.promptLine': '{category}: {objects} oggetti ({size}) da {from} a {to}', + 'storage.migrate.promptLine': '{category}: {count} oggetti ({size}) da {from} a {to}', + 'storage.migrate.promptLine.one': '{category}: {count} oggetto ({size}) da {from} a {to}', 'storage.migrate.promptLineUnknown': '{category}: dimensione sconosciuta (utilizzo non ancora calcolato) da {from} a {to}', 'storage.migrate.move': 'Sposta oggetti esistenti', @@ -135,7 +136,8 @@ const storage: TranslationStrings = { 'storage.migrate.doneFailures': '{failed} non riusciti — questi oggetti non sono stati copiati nel nuovo backend', 'storage.migrate.failed': 'Spostamento non riuscito: {error} — la categoria non è stata cambiata', 'storage.migrate.cancelled': 'Spostamento annullato — nulla è stato cambiato', - 'storage.migrate.reclaimable': '{objects} oggetti ({size}) restano su {from} — recuperali manualmente', + 'storage.migrate.reclaimable': '{count} oggetti ({size}) restano su {from}, recuperali manualmente', + 'storage.migrate.reclaimable.one': '{count} oggetto ({size}) resta su {from}, recuperalo manualmente', 'storage.migrate.cancel': 'Annulla spostamento', 'storage.migrate.promptCancel': 'Annulla', 'storage.migrate.queued': 'In coda: {categories}', diff --git a/shared/src/i18n/ja/collab.ts b/shared/src/i18n/ja/collab.ts index 47efbb4df..33bc6bba5 100644 --- a/shared/src/i18n/ja/collab.ts +++ b/shared/src/i18n/ja/collab.ts @@ -96,7 +96,7 @@ const collab: TranslationStrings = { 'collab.polls.options': '選択肢', 'collab.polls.delete': '削除', 'collab.polls.closedSection': '終了', - 'collab.chat.imageLimit': '1件のメッセージに添付できる画像は{max}枚までです', + 'collab.chat.imageLimit': '1件のメッセージに添付できる画像は{count}枚までです', 'collab.chat.uploading': 'アップロード中 {percent}%', 'collab.chat.attachImages': '画像を添付', 'collab.chat.attachedImage': '添付画像', diff --git a/shared/src/i18n/ja/dashboard.ts b/shared/src/i18n/ja/dashboard.ts index 122dd933d..d28a10991 100644 --- a/shared/src/i18n/ja/dashboard.ts +++ b/shared/src/i18n/ja/dashboard.ts @@ -107,7 +107,7 @@ const dashboard: TranslationStrings = { 'dashboard.useUnsplashPhoto': '{photographer}さんのUnsplash写真を使用', 'dashboard.titleRequired': 'タイトルは必須です', 'dashboard.endDateError': '終了日は開始日より後にしてください', - 'dashboard.tripTooLong': '旅行の期間は最大{days}日までです', + 'dashboard.tripTooLong': '旅行の期間は最大{count}日までです', 'dashboard.dateShiftTitle': '新しい開始日', 'dashboard.dateShiftIntro': '旅行の開始日が変更されました。予定を新しい日程にどのように合わせますか?', 'dashboard.dateShiftKeepBookings': '予約を元の日付のままにする', diff --git a/shared/src/i18n/ja/dawarich.ts b/shared/src/i18n/ja/dawarich.ts index 47c9e27ab..71ae8c96b 100644 --- a/shared/src/i18n/ja/dawarich.ts +++ b/shared/src/i18n/ja/dawarich.ts @@ -116,7 +116,7 @@ const dawarich: TranslationStrings = { 'dawarich.accept.confirm.journal': 'エントリーを追加', 'dawarich.accept.confirm.bucket_list': 'チェックを付ける', 'dawarich.accept.recorded': '記録:{from}から{to}まで', - 'dawarich.accept.duration': '{minutes}分', + 'dawarich.accept.duration': '{count}分', 'dawarich.accept.name': '名前', 'dawarich.accept.date': '日付', 'dawarich.accept.from': '到着', @@ -175,7 +175,7 @@ const dawarich: TranslationStrings = { 'dawarich.again': 'もう一度確認', 'dawarich.bucket.metersAway': '{meters} m 先', 'dawarich.bucket.kilometersAway': '{km} km 先', - 'dawarich.bucket.rule': '{meters} m 以内に {minutes} 分以上滞在すると、願いがかなったとみなします。', + 'dawarich.bucket.rule': '{meters} m 以内に {count} 分以上滞在すると、願いがかなったとみなします。', 'dawarich.journey.dayStays.other': 'Dawarich の滞在 {count} 件', }; diff --git a/shared/src/i18n/ja/roadtrip.ts b/shared/src/i18n/ja/roadtrip.ts index 08a84c8e7..72b0f26cf 100644 --- a/shared/src/i18n/ja/roadtrip.ts +++ b/shared/src/i18n/ja/roadtrip.ts @@ -56,7 +56,7 @@ const roadtrip: TranslationStrings = { 'roadtrip.window.incomplete': '毎日の休憩を計算するには、すべての接続ルートが必要です。', 'roadtrip.window.conflict': '固定時刻が移動や休憩と両立しません。手動の時刻は保持され、自動計画は一時停止しています。', - 'roadtrip.window.tooLong': 'この設定では{days}日を超える追加日数が必要です。一日の移動時間を長くしてください。', + 'roadtrip.window.tooLong': 'この設定では{count}日を超える追加日数が必要です。一日の移動時間を長くしてください。', 'roadtrip.mode.roadtrip': 'ロードトリップ', 'roadtrip.mode.days': '日ごと', 'roadtrip.mode.label': 'プラン表示', @@ -102,8 +102,8 @@ const roadtrip: TranslationStrings = { 'roadtrip.limit.minutes': '分', 'roadtrip.limit.off': 'なし', 'roadtrip.limit.blockNote': '1ブロック = {distance}', - 'roadtrip.limit.echoOver': '{days}日のうち{over}日が上限超過。', - 'roadtrip.limit.echoNone': '{days}日すべてが上限内です。', + 'roadtrip.limit.echoOver': '{count}日のうち{over}日が上限超過。', + 'roadtrip.limit.echoNone': '{count}日すべてが上限内です。', 'roadtrip.limit.echoDry': '到達できる立ち寄り先のない区間が{count}件。', 'roadtrip.limit.echoEmpty': 'ロードトリップを開くと効果が見えます。', 'roadtrip.limit.specToggle': '車のデータから計算する', @@ -258,8 +258,8 @@ const roadtrip: TranslationStrings = { 'roadtrip.stop.computed': '運転時間からの計算値', 'roadtrip.stop.endIsLeave': 'ロードトリップでは、この時刻に出発します。', 'roadtrip.via.hint': 'ドラッグでルートを変え、右クリックで削除', - 'roadtrip.warn.late': '設定した時刻より {minutes} 分遅く到着します', - 'roadtrip.warn.missedLeave': '設定した出発時刻より {minutes} 分遅く到着します', + 'roadtrip.warn.late': '設定した時刻より {count} 分遅く到着します', + 'roadtrip.warn.missedLeave': '設定した出発時刻より {count} 分遅く到着します', 'roadtrip.warn.overnight': '翌日', 'roadtrip.spill.title': '{number}日目から', 'roadtrip.spill.departs': '{time} 発', diff --git a/shared/src/i18n/ja/settings.ts b/shared/src/i18n/ja/settings.ts index 874b9d1df..d89c3271e 100644 --- a/shared/src/i18n/ja/settings.ts +++ b/shared/src/i18n/ja/settings.ts @@ -592,7 +592,7 @@ const settings: TranslationStrings = { 'settings.apiKeys.endpoint': 'エンドポイント', 'settings.apiKeys.neverUsed': '未使用', 'settings.apiKeys.loadFailed': 'キーを読み込めませんでした。ページを再読み込みしてもう一度お試しください。', - 'settings.apiKeys.limitReached': 'キーは {max} 個あり、1 アカウントの上限に達しています。新しく作成するには、使わなくなったキーを削除してください。', + 'settings.apiKeys.limitReached': 'キーは {count} 個あり、1 アカウントの上限に達しています。新しく作成するには、使わなくなったキーを削除してください。', 'settings.apiKeys.copyFailed': 'コピーできませんでした。テキストを選択して手動でコピーしてください。', 'settings.apiKeys.modal.createTitle': 'API キーを作成', 'settings.apiKeys.modal.name': '名前', diff --git a/shared/src/i18n/ja/storage.ts b/shared/src/i18n/ja/storage.ts index 09de172f6..417eaafb8 100644 --- a/shared/src/i18n/ja/storage.ts +++ b/shared/src/i18n/ja/storage.ts @@ -121,7 +121,7 @@ const storage: TranslationStrings = { // Category migration (copy → flip → delta sweep) 'storage.migrate.promptTitle': '既存のオブジェクトを新しいバックエンドに移動しますか?', - 'storage.migrate.promptLine': '{category}: {from}から{to}へ {objects}件のオブジェクト({size})', + 'storage.migrate.promptLine': '{category}: {from}から{to}へ {count}件のオブジェクト({size})', 'storage.migrate.promptLineUnknown': '{category}: サイズ不明(使用量スキャン未実施){from}から{to}へ', 'storage.migrate.move': '既存のオブジェクトを移動', 'storage.migrate.routeOnly': '新規書き込みのみ切り替える', @@ -130,7 +130,7 @@ const storage: TranslationStrings = { 'storage.migrate.doneFailures': '{failed}件失敗 — それらのオブジェクトは新しいバックエンドにコピーされませんでした', 'storage.migrate.failed': '移動に失敗しました: {error} — カテゴリは切り替えられませんでした', 'storage.migrate.cancelled': '移動をキャンセルしました — 何も切り替えられていません', - 'storage.migrate.reclaimable': '{objects}件のオブジェクト({size})が{from}に残っています — 手動で回収してください', + 'storage.migrate.reclaimable': '{count}件のオブジェクト({size})が{from}に残っています。手動で回収してください', 'storage.migrate.cancel': '移動をキャンセル', 'storage.migrate.promptCancel': 'キャンセル', 'storage.migrate.queued': 'キュー待ち: {categories}', diff --git a/shared/src/i18n/ko/collab.ts b/shared/src/i18n/ko/collab.ts index ef9cf6ddb..f9009b984 100644 --- a/shared/src/i18n/ko/collab.ts +++ b/shared/src/i18n/ko/collab.ts @@ -96,7 +96,7 @@ const collab: TranslationStrings = { 'collab.polls.options': '옵션', 'collab.polls.delete': '삭제', 'collab.polls.closedSection': '종료됨', - 'collab.chat.imageLimit': '메시지당 최대 {max}장의 이미지를 첨부할 수 있습니다', + 'collab.chat.imageLimit': '메시지당 최대 {count}장의 이미지를 첨부할 수 있습니다', 'collab.chat.uploading': '업로드 중 {percent}%', 'collab.chat.attachImages': '이미지 첨부', 'collab.chat.attachedImage': '첨부된 이미지', diff --git a/shared/src/i18n/ko/dashboard.ts b/shared/src/i18n/ko/dashboard.ts index 92da95cc8..f5ee267e2 100644 --- a/shared/src/i18n/ko/dashboard.ts +++ b/shared/src/i18n/ko/dashboard.ts @@ -107,7 +107,7 @@ const dashboard: TranslationStrings = { 'dashboard.useUnsplashPhoto': '{photographer}님의 Unsplash 사진 사용', 'dashboard.titleRequired': '제목을 입력하세요', 'dashboard.endDateError': '종료일은 시작일 이후여야 합니다', - 'dashboard.tripTooLong': '여행 기간은 최대 {days}일까지입니다', + 'dashboard.tripTooLong': '여행 기간은 최대 {count}일까지입니다', 'dashboard.dateShiftTitle': '새 시작일', 'dashboard.dateShiftIntro': '여행 시작일이 변경되었습니다. 계획을 새 날짜에 어떻게 맞출까요?', 'dashboard.dateShiftKeepBookings': '예약은 원래 날짜에 유지', diff --git a/shared/src/i18n/ko/dawarich.ts b/shared/src/i18n/ko/dawarich.ts index 9b43f21fb..032f848ab 100644 --- a/shared/src/i18n/ko/dawarich.ts +++ b/shared/src/i18n/ko/dawarich.ts @@ -112,7 +112,7 @@ const dawarich: TranslationStrings = { 'dawarich.accept.confirm.journal': '항목 추가', 'dawarich.accept.confirm.bucket_list': '완료 처리', 'dawarich.accept.recorded': '{from}부터 {to}까지 기록됨', - 'dawarich.accept.duration': '{minutes}분', + 'dawarich.accept.duration': '{count}분', 'dawarich.accept.name': '이름', 'dawarich.accept.date': '날짜', 'dawarich.accept.from': '도착', @@ -170,7 +170,7 @@ const dawarich: TranslationStrings = { 'dawarich.again': '다시 확인', 'dawarich.bucket.metersAway': '{meters} m 거리', 'dawarich.bucket.kilometersAway': '{km} km 거리', - 'dawarich.bucket.rule': '{meters} m 이내에서 {minutes}분 이상 머무르면 소원을 이룬 것으로 봅니다.', + 'dawarich.bucket.rule': '{meters} m 이내에서 {count}분 이상 머무르면 소원을 이룬 것으로 봅니다.', 'dawarich.journey.dayStays.other': 'Dawarich 방문 기록 {count}건', }; diff --git a/shared/src/i18n/ko/roadtrip.ts b/shared/src/i18n/ko/roadtrip.ts index 2a36ff761..b4aff5547 100644 --- a/shared/src/i18n/ko/roadtrip.ts +++ b/shared/src/i18n/ko/roadtrip.ts @@ -55,7 +55,7 @@ const roadtrip: TranslationStrings = { 'roadtrip.window.incomplete': '매일 휴식을 계산하려면 모든 연결 경로가 필요합니다.', 'roadtrip.window.conflict': '고정 시간이 이동 및 휴식과 충돌합니다. 수동 시간은 유지되며 자동 계획이 일시 중지됩니다.', - 'roadtrip.window.tooLong': '이 시간 설정에는 {days}일이 넘는 추가 날짜가 필요합니다. 일일 이동 시간을 늘려 주세요.', + 'roadtrip.window.tooLong': '이 시간 설정에는 {count}일이 넘는 추가 날짜가 필요합니다. 일일 이동 시간을 늘려 주세요.', 'roadtrip.mode.roadtrip': '로드트립', 'roadtrip.mode.days': '일자별', 'roadtrip.mode.label': '계획 보기', @@ -101,8 +101,8 @@ const roadtrip: TranslationStrings = { 'roadtrip.limit.minutes': '분', 'roadtrip.limit.off': '끔', 'roadtrip.limit.blockNote': '한 블록 = {distance}', - 'roadtrip.limit.echoOver': '{days}일 중 {over}일이 한도 초과.', - 'roadtrip.limit.echoNone': '{days}일 모두 한도 안입니다.', + 'roadtrip.limit.echoOver': '{count}일 중 {over}일이 한도 초과.', + 'roadtrip.limit.echoNone': '{count}일 모두 한도 안입니다.', 'roadtrip.limit.echoDry': '도달 가능한 정차지가 없는 구간 {count}곳.', 'roadtrip.limit.echoEmpty': '로드트립을 열면 효과가 보입니다.', 'roadtrip.limit.specToggle': '차량 데이터로 계산하기', @@ -255,8 +255,8 @@ const roadtrip: TranslationStrings = { 'roadtrip.stop.computed': '주행 시간으로 계산됨', 'roadtrip.stop.endIsLeave': '로드트립에서는 이 시간에 출발합니다.', 'roadtrip.via.hint': '끌어서 경로를 바꾸고, 오른쪽 클릭으로 삭제', - 'roadtrip.warn.late': '지정한 시간보다 {minutes}분 늦게 도착', - 'roadtrip.warn.missedLeave': '지정한 출발 시간보다 {minutes}분 늦게 도착', + 'roadtrip.warn.late': '지정한 시간보다 {count}분 늦게 도착', + 'roadtrip.warn.missedLeave': '지정한 출발 시간보다 {count}분 늦게 도착', 'roadtrip.warn.overnight': '다음 날', 'roadtrip.spill.title': '{number}일차에서', 'roadtrip.spill.departs': '{time} 출발', diff --git a/shared/src/i18n/ko/settings.ts b/shared/src/i18n/ko/settings.ts index d332872c5..898017f81 100644 --- a/shared/src/i18n/ko/settings.ts +++ b/shared/src/i18n/ko/settings.ts @@ -609,7 +609,7 @@ const settings: TranslationStrings = { 'settings.apiKeys.endpoint': '엔드포인트', 'settings.apiKeys.neverUsed': '사용한 적 없음', 'settings.apiKeys.loadFailed': '키를 불러오지 못했습니다. 페이지를 새로 고친 뒤 다시 시도하세요.', - 'settings.apiKeys.limitReached': '키가 {max}개로 계정당 최대 개수입니다. 새 키를 만들려면 더 이상 쓰지 않는 키를 삭제하세요.', + 'settings.apiKeys.limitReached': '키가 {count}개로 계정당 최대 개수입니다. 새 키를 만들려면 더 이상 쓰지 않는 키를 삭제하세요.', 'settings.apiKeys.copyFailed': '복사하지 못했습니다. 텍스트를 선택해 직접 복사하세요.', 'settings.apiKeys.modal.createTitle': 'API 키 만들기', 'settings.apiKeys.modal.name': '이름', diff --git a/shared/src/i18n/ko/storage.ts b/shared/src/i18n/ko/storage.ts index 856f02ceb..f88a63b37 100644 --- a/shared/src/i18n/ko/storage.ts +++ b/shared/src/i18n/ko/storage.ts @@ -118,7 +118,7 @@ const storage: TranslationStrings = { // Category migration (copy → flip → delta sweep) 'storage.migrate.promptTitle': '기존 객체를 새 백엔드로 이동할까요?', - 'storage.migrate.promptLine': '{category}: {from}에서 {to}(으)로 {objects}개 객체 ({size})', + 'storage.migrate.promptLine': '{category}: {from}에서 {to}(으)로 {count}개 객체 ({size})', 'storage.migrate.promptLineUnknown': '{category}: 크기 알 수 없음 (아직 사용량 스캔 안 됨) {from}에서 {to}(으)로', 'storage.migrate.move': '기존 객체 이동', 'storage.migrate.routeOnly': '새 쓰기만 전환', @@ -127,7 +127,7 @@ const storage: TranslationStrings = { 'storage.migrate.doneFailures': '{failed}개 실패 — 해당 객체는 새 백엔드로 복사되지 않았습니다', 'storage.migrate.failed': '이동 실패: {error} — 카테고리가 전환되지 않았습니다', 'storage.migrate.cancelled': '이동이 취소되었습니다 — 아무것도 전환되지 않았습니다', - 'storage.migrate.reclaimable': '{objects}개 객체 ({size})가 {from}에 남아 있습니다 — 수동으로 회수하세요', + 'storage.migrate.reclaimable': '{count}개 객체 ({size})가 {from}에 남아 있습니다. 수동으로 회수하세요', 'storage.migrate.cancel': '이동 취소', 'storage.migrate.promptCancel': '취소', 'storage.migrate.queued': '대기 중: {categories}', diff --git a/shared/src/i18n/nl/collab.ts b/shared/src/i18n/nl/collab.ts index 72b3db932..5b1b0d92c 100644 --- a/shared/src/i18n/nl/collab.ts +++ b/shared/src/i18n/nl/collab.ts @@ -100,7 +100,8 @@ const collab: TranslationStrings = { 'collab.polls.options': 'Opties', 'collab.polls.delete': 'Verwijderen', 'collab.polls.closedSection': 'Gesloten', - 'collab.chat.imageLimit': 'Je kunt maximaal {max} afbeeldingen per bericht toevoegen', + 'collab.chat.imageLimit': 'Je kunt maximaal {count} afbeeldingen per bericht toevoegen', + 'collab.chat.imageLimit.one': 'Je kunt maar {count} afbeelding per bericht toevoegen', 'collab.chat.uploading': 'Uploaden {percent}%', 'collab.chat.attachImages': 'Afbeeldingen toevoegen', 'collab.chat.attachedImage': 'Bijgevoegde afbeelding', diff --git a/shared/src/i18n/nl/dashboard.ts b/shared/src/i18n/nl/dashboard.ts index e26827969..1b0eae22d 100644 --- a/shared/src/i18n/nl/dashboard.ts +++ b/shared/src/i18n/nl/dashboard.ts @@ -99,7 +99,8 @@ const dashboard: TranslationStrings = { 'dashboard.useUnsplashPhoto': 'Unsplash-foto van {photographer} gebruiken', 'dashboard.titleRequired': 'Titel is verplicht', 'dashboard.endDateError': 'Einddatum moet na de startdatum liggen', - 'dashboard.tripTooLong': 'Een reis kan maximaal {days} dagen duren', + 'dashboard.tripTooLong': 'Een reis kan maximaal {count} dagen duren', + 'dashboard.tripTooLong.one': 'Een reis kan maximaal {count} dag duren', 'dashboard.dateShiftTitle': 'Nieuwe startdatum', 'dashboard.dateShiftIntro': 'Je hebt gewijzigd wanneer deze reis begint. Hoe moeten je plannen de nieuwe datums volgen?', diff --git a/shared/src/i18n/nl/dawarich.ts b/shared/src/i18n/nl/dawarich.ts index 37936ee87..b18145c0b 100644 --- a/shared/src/i18n/nl/dawarich.ts +++ b/shared/src/i18n/nl/dawarich.ts @@ -118,7 +118,8 @@ const dawarich: TranslationStrings = { 'dawarich.accept.confirm.journal': 'Vermelding toevoegen', 'dawarich.accept.confirm.bucket_list': 'Afvinken', 'dawarich.accept.recorded': 'Opgenomen van {from} tot {to}', - 'dawarich.accept.duration': '{minutes} min', + 'dawarich.accept.duration': '{count} min', + 'dawarich.accept.duration.one': '{count} min', 'dawarich.accept.name': 'Naam', 'dawarich.accept.date': 'Datum', 'dawarich.accept.from': 'Aangekomen', @@ -183,7 +184,8 @@ const dawarich: TranslationStrings = { 'dawarich.again': 'Opnieuw controleren', 'dawarich.bucket.metersAway': '{meters} m verderop', 'dawarich.bucket.kilometersAway': '{km} km verderop', - 'dawarich.bucket.rule': 'Een wens telt als bereikt binnen {meters} m en na {minutes} minuten ter plaatse.', + 'dawarich.bucket.rule': 'Een wens telt als bereikt binnen {meters} m en na {count} minuten ter plaatse.', + 'dawarich.bucket.rule.one': 'Een wens telt als bereikt binnen {meters} m en na {count} minuut ter plaatse.', 'dawarich.journey.dayStays.other': '{count} bezoeken uit Dawarich', 'dawarich.journey.dayStays.one': '{count} bezoek uit Dawarich', diff --git a/shared/src/i18n/nl/roadtrip.ts b/shared/src/i18n/nl/roadtrip.ts index ee9fc5000..e2b713e57 100644 --- a/shared/src/i18n/nl/roadtrip.ts +++ b/shared/src/i18n/nl/roadtrip.ts @@ -56,7 +56,8 @@ const roadtrip: TranslationStrings = { 'Dagelijkse pauzes kunnen pas worden berekend als alle verbindingsroutes beschikbaar zijn.', 'roadtrip.window.conflict': 'Een vaste tijd past niet bij de rit en pauzes. Handmatige tijden blijven behouden; automatische planning is gepauzeerd.', - 'roadtrip.window.tooLong': 'Deze tijden vragen meer dan {days} extra dagen. Kies een langer dagelijks tijdvak.', + 'roadtrip.window.tooLong': 'Deze tijden vragen meer dan {count} extra dagen. Kies een langer dagelijks tijdvak.', + 'roadtrip.window.tooLong.one': 'Deze tijden vragen meer dan {count} extra dag. Kies een langer dagelijks tijdvak.', 'roadtrip.mode.roadtrip': 'Roadtrip', 'roadtrip.mode.days': 'Dagen', 'roadtrip.mode.label': 'Planweergave', @@ -104,8 +105,10 @@ const roadtrip: TranslationStrings = { 'roadtrip.limit.minutes': 'min', 'roadtrip.limit.off': 'uit', 'roadtrip.limit.blockNote': 'Eén blok = {distance}', - 'roadtrip.limit.echoOver': '{over} van {days} dagen boven je limiet.', - 'roadtrip.limit.echoNone': 'Alle {days} dagen binnen je limieten.', + 'roadtrip.limit.echoOver': '{over} van {count} dagen boven je limiet.', + 'roadtrip.limit.echoOver.one': '{over} van {count} dag boven je limiet.', + 'roadtrip.limit.echoNone': 'Alle {count} dagen binnen je limieten.', + 'roadtrip.limit.echoNone.one': 'De ene dag binnen je limieten.', 'roadtrip.limit.echoDry': '{count} stukken zonder bereikbare stop.', 'roadtrip.limit.echoDry.one': '{count} stuk zonder bereikbare stop.', 'roadtrip.limit.echoEmpty': 'Open een roadtrip om het effect te zien.', @@ -274,8 +277,10 @@ const roadtrip: TranslationStrings = { 'roadtrip.stop.computed': 'Berekend uit de rit', 'roadtrip.stop.endIsLeave': 'Op de roadtrip vertrek je op dit tijdstip.', 'roadtrip.via.hint': 'Sleep om de route te hervormen, rechtsklik om te verwijderen', - 'roadtrip.warn.late': 'Aankomst {minutes} min na de gezette tijd', - 'roadtrip.warn.missedLeave': 'Aankomst {minutes} min na de gezette vertrektijd', + 'roadtrip.warn.late': 'Aankomst {count} min na de gezette tijd', + 'roadtrip.warn.late.one': 'Aankomst {count} min na de gezette tijd', + 'roadtrip.warn.missedLeave': 'Aankomst {count} min na de gezette vertrektijd', + 'roadtrip.warn.missedLeave.one': 'Aankomst {count} min na de gezette vertrektijd', 'roadtrip.warn.overnight': 'Volgende dag', 'roadtrip.spill.title': 'Van dag {number}', 'roadtrip.spill.departs': 'vertrek {time}', diff --git a/shared/src/i18n/nl/settings.ts b/shared/src/i18n/nl/settings.ts index 8751d90a1..fa426926f 100644 --- a/shared/src/i18n/nl/settings.ts +++ b/shared/src/i18n/nl/settings.ts @@ -633,7 +633,10 @@ const settings: TranslationStrings = { 'settings.apiKeys.endpoint': 'Eindpunt', 'settings.apiKeys.neverUsed': 'nooit gebruikt', 'settings.apiKeys.loadFailed': 'Je sleutels konden niet worden geladen. Herlaad de pagina om het opnieuw te proberen.', - 'settings.apiKeys.limitReached': 'Je hebt {max} sleutels, het maximum per account. Verwijder er een die je niet meer gebruikt om een nieuwe te maken.', + 'settings.apiKeys.limitReached': + 'Je hebt {count} sleutels, het maximum per account. Verwijder er een die je niet meer gebruikt om een nieuwe te maken.', + 'settings.apiKeys.limitReached.one': + 'Je hebt {count} sleutel, het maximum per account. Verwijder hem als je hem niet meer gebruikt om een nieuwe te maken.', 'settings.apiKeys.copyFailed': 'Kopiëren is mislukt. Selecteer de tekst en kopieer hem handmatig.', 'settings.apiKeys.modal.createTitle': 'API-sleutel aanmaken', 'settings.apiKeys.modal.name': 'Naam', diff --git a/shared/src/i18n/nl/storage.ts b/shared/src/i18n/nl/storage.ts index 043ea434b..06b54b7fa 100644 --- a/shared/src/i18n/nl/storage.ts +++ b/shared/src/i18n/nl/storage.ts @@ -125,7 +125,8 @@ const storage: TranslationStrings = { // Category migration (copy → flip → delta sweep) 'storage.migrate.promptTitle': 'Bestaande objecten naar de nieuwe backend verplaatsen?', - 'storage.migrate.promptLine': '{category}: {objects} objecten ({size}) van {from} naar {to}', + 'storage.migrate.promptLine': '{category}: {count} objecten ({size}) van {from} naar {to}', + 'storage.migrate.promptLine.one': '{category}: {count} object ({size}) van {from} naar {to}', 'storage.migrate.promptLineUnknown': '{category}: onbekende grootte (gebruik nog niet gescand) van {from} naar {to}', 'storage.migrate.move': 'Bestaande objecten verplaatsen', 'storage.migrate.routeOnly': 'Alleen nieuwe schrijfacties omleiden', @@ -134,7 +135,8 @@ const storage: TranslationStrings = { 'storage.migrate.doneFailures': '{failed} mislukt — die objecten zijn niet gekopieerd naar de nieuwe backend', 'storage.migrate.failed': 'Verplaatsen mislukt: {error} — de categorie is niet omgezet', 'storage.migrate.cancelled': 'Verplaatsen geannuleerd — er is niets omgezet', - 'storage.migrate.reclaimable': '{objects} objecten ({size}) blijven op {from} — handmatig terugwinnen', + 'storage.migrate.reclaimable': '{count} objecten ({size}) blijven op {from}, handmatig terugwinnen', + 'storage.migrate.reclaimable.one': '{count} object ({size}) blijft op {from}, handmatig terugwinnen', 'storage.migrate.cancel': 'Verplaatsen annuleren', 'storage.migrate.promptCancel': 'Annuleren', 'storage.migrate.queued': 'In wachtrij: {categories}', diff --git a/shared/src/i18n/pl/collab.ts b/shared/src/i18n/pl/collab.ts index d20301cf7..6d1aa0257 100644 --- a/shared/src/i18n/pl/collab.ts +++ b/shared/src/i18n/pl/collab.ts @@ -108,7 +108,10 @@ const collab: TranslationStrings = { 'collab.polls.delete': 'Usuń', 'collab.polls.closedSection': 'Zamknięte', 'collab.chat.reply': 'Odpowiedz', - 'collab.chat.imageLimit': 'Do jednej wiadomości możesz dołączyć maksymalnie {max} obrazów', + 'collab.chat.imageLimit': 'Do jednej wiadomości możesz dołączyć maksymalnie {count} obrazu', + 'collab.chat.imageLimit.one': 'Do jednej wiadomości możesz dołączyć tylko {count} obraz', + 'collab.chat.imageLimit.few': 'Do jednej wiadomości możesz dołączyć maksymalnie {count} obrazy', + 'collab.chat.imageLimit.many': 'Do jednej wiadomości możesz dołączyć maksymalnie {count} obrazów', 'collab.chat.uploading': 'Przesyłanie {percent}%', 'collab.chat.attachImages': 'Dołącz obrazy', 'collab.chat.attachedImage': 'Załączony obraz', diff --git a/shared/src/i18n/pl/dashboard.ts b/shared/src/i18n/pl/dashboard.ts index 2250f3924..f22785b2d 100644 --- a/shared/src/i18n/pl/dashboard.ts +++ b/shared/src/i18n/pl/dashboard.ts @@ -105,7 +105,10 @@ const dashboard: TranslationStrings = { 'dashboard.useUnsplashPhoto': 'Użyj zdjęcia z Unsplash autorstwa {photographer}', 'dashboard.titleRequired': 'Nazwa podróży jest wymagana', 'dashboard.endDateError': 'Data zakończenia musi być po dacie rozpoczęcia', - 'dashboard.tripTooLong': 'Podróż może trwać maksymalnie {days} dni', + 'dashboard.tripTooLong': 'Podróż może trwać maksymalnie {count} dnia', + 'dashboard.tripTooLong.one': 'Podróż może trwać maksymalnie {count} dzień', + 'dashboard.tripTooLong.few': 'Podróż może trwać maksymalnie {count} dni', + 'dashboard.tripTooLong.many': 'Podróż może trwać maksymalnie {count} dni', 'dashboard.dateShiftTitle': 'Nowa data rozpoczęcia', 'dashboard.dateShiftIntro': 'Data rozpoczęcia podróży została zmieniona. Jak plany mają dostosować się do nowych dat?', diff --git a/shared/src/i18n/pl/dawarich.ts b/shared/src/i18n/pl/dawarich.ts index ec62e5c1e..b879f56f0 100644 --- a/shared/src/i18n/pl/dawarich.ts +++ b/shared/src/i18n/pl/dawarich.ts @@ -124,7 +124,10 @@ const dawarich: TranslationStrings = { 'dawarich.accept.confirm.journal': 'Dodaj wpis', 'dawarich.accept.confirm.bucket_list': 'Odhacz', 'dawarich.accept.recorded': 'Zapisano od {from} do {to}', - 'dawarich.accept.duration': '{minutes} min', + 'dawarich.accept.duration': '{count} min', + 'dawarich.accept.duration.one': '{count} min', + 'dawarich.accept.duration.few': '{count} min', + 'dawarich.accept.duration.many': '{count} min', 'dawarich.accept.name': 'Nazwa', 'dawarich.accept.date': 'Data', 'dawarich.accept.from': 'Przyjazd', @@ -203,7 +206,13 @@ const dawarich: TranslationStrings = { 'dawarich.again': 'Sprawdź ponownie', 'dawarich.bucket.metersAway': '{meters} m stąd', 'dawarich.bucket.kilometersAway': '{km} km stąd', - 'dawarich.bucket.rule': 'Marzenie uznaje się za spełnione w promieniu {meters} m i po {minutes} minutach na miejscu.', + 'dawarich.bucket.rule': 'Marzenie uznaje się za spełnione w promieniu {meters} m i po {count} minuty na miejscu.', + 'dawarich.bucket.rule.one': + 'Marzenie uznaje się za spełnione w promieniu {meters} m i po {count} minucie na miejscu.', + 'dawarich.bucket.rule.few': + 'Marzenie uznaje się za spełnione w promieniu {meters} m i po {count} minutach na miejscu.', + 'dawarich.bucket.rule.many': + 'Marzenie uznaje się za spełnione w promieniu {meters} m i po {count} minutach na miejscu.', 'dawarich.journey.dayStays.other': '{count} pobytu z Dawarich', 'dawarich.journey.dayStays.one': '{count} pobyt z Dawarich', 'dawarich.journey.dayStays.few': '{count} pobyty z Dawarich', diff --git a/shared/src/i18n/pl/roadtrip.ts b/shared/src/i18n/pl/roadtrip.ts index 38b88f584..d9ee02d37 100644 --- a/shared/src/i18n/pl/roadtrip.ts +++ b/shared/src/i18n/pl/roadtrip.ts @@ -55,7 +55,12 @@ const roadtrip: TranslationStrings = { 'roadtrip.window.incomplete': 'Obliczenie codziennych przerw wymaga wszystkich tras łączących.', 'roadtrip.window.conflict': 'Stała godzina koliduje z jazdą i przerwami. Ręczne godziny pozostają bez zmian; automatyczne planowanie jest wstrzymane.', - 'roadtrip.window.tooLong': 'Te godziny wymagają ponad {days} dodatkowych dni. Wybierz dłuższy dzienny przedział.', + 'roadtrip.window.tooLong': 'Te godziny wymagają ponad {count} dodatkowego dnia. Wybierz dłuższy dzienny przedział.', + 'roadtrip.window.tooLong.one': + 'Te godziny wymagają ponad {count} dodatkowy dzień. Wybierz dłuższy dzienny przedział.', + 'roadtrip.window.tooLong.few': 'Te godziny wymagają ponad {count} dodatkowe dni. Wybierz dłuższy dzienny przedział.', + 'roadtrip.window.tooLong.many': + 'Te godziny wymagają ponad {count} dodatkowych dni. Wybierz dłuższy dzienny przedział.', 'roadtrip.mode.roadtrip': 'Podróż samochodowa', 'roadtrip.mode.days': 'Dni', 'roadtrip.mode.label': 'Widok planu', @@ -104,8 +109,14 @@ const roadtrip: TranslationStrings = { 'roadtrip.limit.minutes': 'min', 'roadtrip.limit.off': 'wył.', 'roadtrip.limit.blockNote': 'Jeden blok = {distance}', - 'roadtrip.limit.echoOver': '{over} z {days} dni ponad limit.', - 'roadtrip.limit.echoNone': 'Wszystkie {days} dni w granicach.', + 'roadtrip.limit.echoOver': '{over} z {count} dnia ponad limit.', + 'roadtrip.limit.echoOver.one': '{over} z {count} dnia ponad limit.', + 'roadtrip.limit.echoOver.few': '{over} z {count} dni ponad limit.', + 'roadtrip.limit.echoOver.many': '{over} z {count} dni ponad limit.', + 'roadtrip.limit.echoNone': 'Wszystkie {count} dni w granicach.', + 'roadtrip.limit.echoNone.one': 'Jedyny dzień w granicach.', + 'roadtrip.limit.echoNone.few': 'Wszystkie {count} dni w granicach.', + 'roadtrip.limit.echoNone.many': 'Wszystkie {count} dni w granicach.', 'roadtrip.limit.echoDry': '{count} odcinka bez osiągalnego postoju.', 'roadtrip.limit.echoDry.one': '{count} odcinek bez osiągalnego postoju.', 'roadtrip.limit.echoDry.few': '{count} odcinki bez osiągalnego postoju.', @@ -295,8 +306,14 @@ const roadtrip: TranslationStrings = { 'roadtrip.stop.computed': 'Obliczone na podstawie jazdy', 'roadtrip.stop.endIsLeave': 'W podróży samochodowej odjazd następuje o tej godzinie.', 'roadtrip.via.hint': 'Przeciągnij, aby zmienić trasę, kliknij prawym, aby usunąć', - 'roadtrip.warn.late': 'Przyjazd {minutes} min po ustawionej godzinie', - 'roadtrip.warn.missedLeave': 'Przyjazd {minutes} min po ustawionej godzinie odjazdu', + 'roadtrip.warn.late': 'Przyjazd {count} min po ustawionej godzinie', + 'roadtrip.warn.late.one': 'Przyjazd {count} min po ustawionej godzinie', + 'roadtrip.warn.late.few': 'Przyjazd {count} min po ustawionej godzinie', + 'roadtrip.warn.late.many': 'Przyjazd {count} min po ustawionej godzinie', + 'roadtrip.warn.missedLeave': 'Przyjazd {count} min po ustawionej godzinie odjazdu', + 'roadtrip.warn.missedLeave.one': 'Przyjazd {count} min po ustawionej godzinie odjazdu', + 'roadtrip.warn.missedLeave.few': 'Przyjazd {count} min po ustawionej godzinie odjazdu', + 'roadtrip.warn.missedLeave.many': 'Przyjazd {count} min po ustawionej godzinie odjazdu', 'roadtrip.warn.overnight': 'Następny dzień', 'roadtrip.spill.title': 'Z dnia {number}', 'roadtrip.spill.departs': 'odjazd {time}', diff --git a/shared/src/i18n/pl/settings.ts b/shared/src/i18n/pl/settings.ts index 2e192f10c..df1e83ac6 100644 --- a/shared/src/i18n/pl/settings.ts +++ b/shared/src/i18n/pl/settings.ts @@ -643,7 +643,14 @@ const settings: TranslationStrings = { 'settings.apiKeys.endpoint': 'Endpoint', 'settings.apiKeys.neverUsed': 'nigdy nieużywany', 'settings.apiKeys.loadFailed': 'Nie udało się wczytać kluczy. Odśwież stronę, aby spróbować ponownie.', - 'settings.apiKeys.limitReached': 'Masz {max} kluczy, czyli maksimum na konto. Usuń klucz, którego już nie używasz, aby utworzyć nowy.', + 'settings.apiKeys.limitReached': + 'Masz {count} klucza, czyli maksimum na konto. Usuń klucz, którego już nie używasz, aby utworzyć nowy.', + 'settings.apiKeys.limitReached.one': + 'Masz {count} klucz, czyli maksimum na konto. Usuń go, jeśli już go nie używasz, aby utworzyć nowy.', + 'settings.apiKeys.limitReached.few': + 'Masz {count} klucze, czyli maksimum na konto. Usuń klucz, którego już nie używasz, aby utworzyć nowy.', + 'settings.apiKeys.limitReached.many': + 'Masz {count} kluczy, czyli maksimum na konto. Usuń klucz, którego już nie używasz, aby utworzyć nowy.', 'settings.apiKeys.copyFailed': 'Nie udało się skopiować. Zaznacz tekst i skopiuj go ręcznie.', 'settings.apiKeys.modal.createTitle': 'Utwórz klucz API', 'settings.apiKeys.modal.name': 'Nazwa', diff --git a/shared/src/i18n/pl/storage.ts b/shared/src/i18n/pl/storage.ts index b96f34610..3a7b33468 100644 --- a/shared/src/i18n/pl/storage.ts +++ b/shared/src/i18n/pl/storage.ts @@ -125,7 +125,10 @@ const storage: TranslationStrings = { // Category migration (copy → flip → delta sweep) 'storage.migrate.promptTitle': 'Przenieść istniejące obiekty do nowego backendu?', - 'storage.migrate.promptLine': '{category}: {objects} obiektów ({size}) z {from} do {to}', + 'storage.migrate.promptLine': '{category}: {count} obiektu ({size}) z {from} do {to}', + 'storage.migrate.promptLine.one': '{category}: {count} obiekt ({size}) z {from} do {to}', + 'storage.migrate.promptLine.few': '{category}: {count} obiekty ({size}) z {from} do {to}', + 'storage.migrate.promptLine.many': '{category}: {count} obiektów ({size}) z {from} do {to}', 'storage.migrate.promptLineUnknown': '{category}: nieznany rozmiar (wykorzystanie jeszcze nie obliczone) z {from} do {to}', 'storage.migrate.move': 'Przenieś istniejące obiekty', @@ -135,7 +138,10 @@ const storage: TranslationStrings = { 'storage.migrate.doneFailures': '{failed} nie powiodło się — te obiekty nie zostały skopiowane do nowego backendu', 'storage.migrate.failed': 'Przenoszenie nie powiodło się: {error} — kategoria nie została przełączona', 'storage.migrate.cancelled': 'Przenoszenie anulowane — nic nie zostało przełączone', - 'storage.migrate.reclaimable': '{objects} obiektów ({size}) pozostaje na {from} — odzyskaj ręcznie', + 'storage.migrate.reclaimable': '{count} obiektu ({size}) pozostaje na {from}, odzyskaj ręcznie', + 'storage.migrate.reclaimable.one': '{count} obiekt ({size}) pozostaje na {from}, odzyskaj ręcznie', + 'storage.migrate.reclaimable.few': '{count} obiekty ({size}) pozostają na {from}, odzyskaj ręcznie', + 'storage.migrate.reclaimable.many': '{count} obiektów ({size}) pozostaje na {from}, odzyskaj ręcznie', 'storage.migrate.cancel': 'Anuluj przenoszenie', 'storage.migrate.promptCancel': 'Anuluj', 'storage.migrate.queued': 'W kolejce: {categories}', diff --git a/shared/src/i18n/ru/collab.ts b/shared/src/i18n/ru/collab.ts index 247487a66..6a8941064 100644 --- a/shared/src/i18n/ru/collab.ts +++ b/shared/src/i18n/ru/collab.ts @@ -108,7 +108,10 @@ const collab: TranslationStrings = { 'collab.polls.options': 'Варианты', 'collab.polls.delete': 'Удалить', 'collab.polls.closedSection': 'Закрытые', - 'collab.chat.imageLimit': 'К одному сообщению можно прикрепить до {max} изображений', + 'collab.chat.imageLimit': 'К одному сообщению можно прикрепить до {count} изображения', + 'collab.chat.imageLimit.one': 'К одному сообщению можно прикрепить до {count} изображения', + 'collab.chat.imageLimit.few': 'К одному сообщению можно прикрепить до {count} изображений', + 'collab.chat.imageLimit.many': 'К одному сообщению можно прикрепить до {count} изображений', 'collab.chat.uploading': 'Загрузка {percent}%', 'collab.chat.attachImages': 'Прикрепить изображения', 'collab.chat.attachedImage': 'Прикреплённое изображение', diff --git a/shared/src/i18n/ru/dashboard.ts b/shared/src/i18n/ru/dashboard.ts index e06ce70b2..a9204711e 100644 --- a/shared/src/i18n/ru/dashboard.ts +++ b/shared/src/i18n/ru/dashboard.ts @@ -113,7 +113,10 @@ const dashboard: TranslationStrings = { 'dashboard.useUnsplashPhoto': 'Использовать фото Unsplash от {photographer}', 'dashboard.titleRequired': 'Название обязательно', 'dashboard.endDateError': 'Дата окончания должна быть позже даты начала', - 'dashboard.tripTooLong': 'Поездка может длиться не более {days} дней', + 'dashboard.tripTooLong': 'Поездка может длиться не более {count} дня', + 'dashboard.tripTooLong.one': 'Поездка может длиться не более {count} дня', + 'dashboard.tripTooLong.few': 'Поездка может длиться не более {count} дней', + 'dashboard.tripTooLong.many': 'Поездка может длиться не более {count} дней', 'dashboard.dateShiftTitle': 'Новая дата начала', 'dashboard.dateShiftIntro': 'Вы изменили дату начала поездки. Как перенести ваши планы на новые даты?', 'dashboard.dateShiftKeepBookings': 'Оставить бронирования на своих датах', diff --git a/shared/src/i18n/ru/dawarich.ts b/shared/src/i18n/ru/dawarich.ts index 3bfba7739..47a544461 100644 --- a/shared/src/i18n/ru/dawarich.ts +++ b/shared/src/i18n/ru/dawarich.ts @@ -124,7 +124,10 @@ const dawarich: TranslationStrings = { 'dawarich.accept.confirm.journal': 'Добавить запись', 'dawarich.accept.confirm.bucket_list': 'Отметить', 'dawarich.accept.recorded': 'Записано с {from} по {to}', - 'dawarich.accept.duration': '{minutes} мин', + 'dawarich.accept.duration': '{count} мин', + 'dawarich.accept.duration.one': '{count} мин', + 'dawarich.accept.duration.few': '{count} мин', + 'dawarich.accept.duration.many': '{count} мин', 'dawarich.accept.name': 'Название', 'dawarich.accept.date': 'Дата', 'dawarich.accept.from': 'Прибытие', @@ -203,7 +206,10 @@ const dawarich: TranslationStrings = { 'dawarich.again': 'Проверить снова', 'dawarich.bucket.metersAway': 'в {meters} м', 'dawarich.bucket.kilometersAway': 'в {km} км', - 'dawarich.bucket.rule': 'Желание считается исполненным в пределах {meters} м и после {minutes} минут на месте.', + 'dawarich.bucket.rule': 'Желание считается исполненным в пределах {meters} м и после {count} минуты на месте.', + 'dawarich.bucket.rule.one': 'Желание считается исполненным в пределах {meters} м и после {count} минуты на месте.', + 'dawarich.bucket.rule.few': 'Желание считается исполненным в пределах {meters} м и после {count} минут на месте.', + 'dawarich.bucket.rule.many': 'Желание считается исполненным в пределах {meters} м и после {count} минут на месте.', 'dawarich.journey.dayStays.other': '{count} остановки из Dawarich', 'dawarich.journey.dayStays.one': '{count} остановка из Dawarich', 'dawarich.journey.dayStays.few': '{count} остановки из Dawarich', diff --git a/shared/src/i18n/ru/roadtrip.ts b/shared/src/i18n/ru/roadtrip.ts index b5da1bc94..f23f242aa 100644 --- a/shared/src/i18n/ru/roadtrip.ts +++ b/shared/src/i18n/ru/roadtrip.ts @@ -56,7 +56,13 @@ const roadtrip: TranslationStrings = { 'roadtrip.window.conflict': 'Фиксированное время противоречит поездке и перерывам. Ручные значения сохранены; автоматическое планирование приостановлено.', 'roadtrip.window.tooLong': - 'При этих настройках потребуется более {days} дополнительных дней. Увеличьте ежедневный интервал.', + 'При этих настройках потребуется более {count} дополнительного дня. Увеличьте ежедневный интервал.', + 'roadtrip.window.tooLong.one': + 'При этих настройках потребуется более {count} дополнительного дня. Увеличьте ежедневный интервал.', + 'roadtrip.window.tooLong.few': + 'При этих настройках потребуется более {count} дополнительных дней. Увеличьте ежедневный интервал.', + 'roadtrip.window.tooLong.many': + 'При этих настройках потребуется более {count} дополнительных дней. Увеличьте ежедневный интервал.', 'roadtrip.mode.roadtrip': 'Автопутешествие', 'roadtrip.mode.days': 'Дни', 'roadtrip.mode.label': 'Вид плана', @@ -105,8 +111,14 @@ const roadtrip: TranslationStrings = { 'roadtrip.limit.minutes': 'мин', 'roadtrip.limit.off': 'выкл', 'roadtrip.limit.blockNote': 'Один блок = {distance}', - 'roadtrip.limit.echoOver': '{over} из {days} дней сверх лимита.', - 'roadtrip.limit.echoNone': 'Все {days} дней в пределах лимитов.', + 'roadtrip.limit.echoOver': '{over} из {count} дня сверх лимита.', + 'roadtrip.limit.echoOver.one': '{over} из {count} дня сверх лимита.', + 'roadtrip.limit.echoOver.few': '{over} из {count} дней сверх лимита.', + 'roadtrip.limit.echoOver.many': '{over} из {count} дней сверх лимита.', + 'roadtrip.limit.echoNone': 'Все {count} дня в пределах лимитов.', + 'roadtrip.limit.echoNone.one': '{count} день в пределах лимитов.', + 'roadtrip.limit.echoNone.few': 'Все {count} дня в пределах лимитов.', + 'roadtrip.limit.echoNone.many': 'Все {count} дней в пределах лимитов.', 'roadtrip.limit.echoDry': '{count} участка без достижимой остановки.', 'roadtrip.limit.echoDry.one': '{count} участок без достижимой остановки.', 'roadtrip.limit.echoDry.few': '{count} участка без достижимой остановки.', @@ -300,8 +312,14 @@ const roadtrip: TranslationStrings = { 'roadtrip.stop.computed': 'Рассчитано по времени в пути', 'roadtrip.stop.endIsLeave': 'В автопутешествии отправление будет в это время.', 'roadtrip.via.hint': 'Перетащите, чтобы изменить маршрут, правый клик — удалить', - 'roadtrip.warn.late': 'Прибытие на {minutes} мин позже заданного времени', - 'roadtrip.warn.missedLeave': 'Прибытие на {minutes} мин позже заданного времени отправления', + 'roadtrip.warn.late': 'Прибытие на {count} мин позже заданного времени', + 'roadtrip.warn.late.one': 'Прибытие на {count} мин позже заданного времени', + 'roadtrip.warn.late.few': 'Прибытие на {count} мин позже заданного времени', + 'roadtrip.warn.late.many': 'Прибытие на {count} мин позже заданного времени', + 'roadtrip.warn.missedLeave': 'Прибытие на {count} мин позже заданного времени отправления', + 'roadtrip.warn.missedLeave.one': 'Прибытие на {count} мин позже заданного времени отправления', + 'roadtrip.warn.missedLeave.few': 'Прибытие на {count} мин позже заданного времени отправления', + 'roadtrip.warn.missedLeave.many': 'Прибытие на {count} мин позже заданного времени отправления', 'roadtrip.warn.overnight': 'Следующий день', 'roadtrip.spill.title': 'Со дня {number}', 'roadtrip.spill.departs': 'выезд {time}', diff --git a/shared/src/i18n/ru/settings.ts b/shared/src/i18n/ru/settings.ts index 8d0e7c53f..fafa5b186 100644 --- a/shared/src/i18n/ru/settings.ts +++ b/shared/src/i18n/ru/settings.ts @@ -648,7 +648,14 @@ const settings: TranslationStrings = { 'settings.apiKeys.endpoint': 'Эндпоинт', 'settings.apiKeys.neverUsed': 'не использовался', 'settings.apiKeys.loadFailed': 'Не удалось загрузить ключи. Обновите страницу, чтобы попробовать снова.', - 'settings.apiKeys.limitReached': 'У вас {max} ключей, это максимум для одного аккаунта. Удалите ненужный ключ, чтобы создать новый.', + 'settings.apiKeys.limitReached': + 'У вас {count} ключа, это максимум для одного аккаунта. Удалите ненужный ключ, чтобы создать новый.', + 'settings.apiKeys.limitReached.one': + 'У вас {count} ключ, это максимум для одного аккаунта. Удалите ненужный ключ, чтобы создать новый.', + 'settings.apiKeys.limitReached.few': + 'У вас {count} ключа, это максимум для одного аккаунта. Удалите ненужный ключ, чтобы создать новый.', + 'settings.apiKeys.limitReached.many': + 'У вас {count} ключей, это максимум для одного аккаунта. Удалите ненужный ключ, чтобы создать новый.', 'settings.apiKeys.copyFailed': 'Не удалось скопировать. Выделите текст и скопируйте его вручную.', 'settings.apiKeys.modal.createTitle': 'Создать ключ API', 'settings.apiKeys.modal.name': 'Название', diff --git a/shared/src/i18n/ru/storage.ts b/shared/src/i18n/ru/storage.ts index 3f8207f28..5da8a7a82 100644 --- a/shared/src/i18n/ru/storage.ts +++ b/shared/src/i18n/ru/storage.ts @@ -127,7 +127,10 @@ const storage: TranslationStrings = { // Category migration (copy → flip → delta sweep) 'storage.migrate.promptTitle': 'Перенести существующие объекты на новый бэкенд?', - 'storage.migrate.promptLine': '{category}: {objects} объектов ({size}) из {from} в {to}', + 'storage.migrate.promptLine': '{category}: {count} объекта ({size}) из {from} в {to}', + 'storage.migrate.promptLine.one': '{category}: {count} объект ({size}) из {from} в {to}', + 'storage.migrate.promptLine.few': '{category}: {count} объекта ({size}) из {from} в {to}', + 'storage.migrate.promptLine.many': '{category}: {count} объектов ({size}) из {from} в {to}', 'storage.migrate.promptLineUnknown': '{category}: неизвестный размер (использование ещё не просканировано) из {from} в {to}', 'storage.migrate.move': 'Перенести существующие объекты', @@ -137,7 +140,10 @@ const storage: TranslationStrings = { 'storage.migrate.doneFailures': '{failed} не удалось — эти объекты не были скопированы на новый бэкенд', 'storage.migrate.failed': 'Перенос не удался: {error} — категория не была переключена', 'storage.migrate.cancelled': 'Перенос отменён — ничего не было переключено', - 'storage.migrate.reclaimable': '{objects} объектов ({size}) остаются на {from} — освободите вручную', + 'storage.migrate.reclaimable': '{count} объекта ({size}) остаются на {from}, освободите вручную', + 'storage.migrate.reclaimable.one': '{count} объект ({size}) остаётся на {from}, освободите вручную', + 'storage.migrate.reclaimable.few': '{count} объекта ({size}) остаются на {from}, освободите вручную', + 'storage.migrate.reclaimable.many': '{count} объектов ({size}) остаются на {from}, освободите вручную', 'storage.migrate.cancel': 'Отменить перенос', 'storage.migrate.promptCancel': 'Отмена', 'storage.migrate.queued': 'В очереди: {categories}', diff --git a/shared/src/i18n/sk/collab.ts b/shared/src/i18n/sk/collab.ts index fc3cd39ca..2d0fe1b60 100644 --- a/shared/src/i18n/sk/collab.ts +++ b/shared/src/i18n/sk/collab.ts @@ -104,7 +104,9 @@ const collab: TranslationStrings = { 'collab.polls.options': 'Možnosti', 'collab.polls.delete': 'Vymazať', 'collab.polls.closedSection': 'Uzavreté', - 'collab.chat.imageLimit': 'K jednej správe môžete priložiť najviac {max} obrázkov', + 'collab.chat.imageLimit': 'K jednej správe môžete priložiť najviac {count} obrázkov', + 'collab.chat.imageLimit.one': 'K jednej správe môžete priložiť iba {count} obrázok', + 'collab.chat.imageLimit.few': 'K jednej správe môžete priložiť najviac {count} obrázky', 'collab.chat.uploading': 'Nahráva sa {percent} %', 'collab.chat.attachImages': 'Priložiť obrázky', 'collab.chat.attachedImage': 'Priložený obrázok', diff --git a/shared/src/i18n/sk/dashboard.ts b/shared/src/i18n/sk/dashboard.ts index d8909b808..577815ba9 100644 --- a/shared/src/i18n/sk/dashboard.ts +++ b/shared/src/i18n/sk/dashboard.ts @@ -120,7 +120,9 @@ const dashboard: TranslationStrings = { 'dashboard.useUnsplashPhoto': 'Použiť fotku z Unsplash od {photographer}', 'dashboard.titleRequired': 'Názov je povinný', 'dashboard.endDateError': 'Dátum konca musí byť po dátume začiatku', - 'dashboard.tripTooLong': 'Cesta môže trvať najviac {days} dní', + 'dashboard.tripTooLong': 'Cesta môže trvať najviac {count} dní', + 'dashboard.tripTooLong.one': 'Cesta môže trvať najviac {count} deň', + 'dashboard.tripTooLong.few': 'Cesta môže trvať najviac {count} dni', 'dashboard.dateShiftTitle': 'Nový dátum začiatku', 'dashboard.dateShiftIntro': 'Zmenili ste začiatok tejto cesty. Ako sa majú vaše plány prispôsobiť novým termínom?', 'dashboard.dateShiftKeepBookings': 'Ponechať rezervácie v pôvodných termínoch', diff --git a/shared/src/i18n/sk/dawarich.ts b/shared/src/i18n/sk/dawarich.ts index 099d55e9b..2d641a95e 100644 --- a/shared/src/i18n/sk/dawarich.ts +++ b/shared/src/i18n/sk/dawarich.ts @@ -122,7 +122,9 @@ const dawarich: TranslationStrings = { 'dawarich.accept.confirm.journal': 'Pridať záznam', 'dawarich.accept.confirm.bucket_list': 'Odškrtnúť', 'dawarich.accept.recorded': 'Zaznamenané od {from} do {to}', - 'dawarich.accept.duration': '{minutes} min', + 'dawarich.accept.duration': '{count} min', + 'dawarich.accept.duration.one': '{count} min', + 'dawarich.accept.duration.few': '{count} min', 'dawarich.accept.name': 'Názov', 'dawarich.accept.date': 'Dátum', 'dawarich.accept.from': 'Príchod', @@ -194,7 +196,9 @@ const dawarich: TranslationStrings = { 'dawarich.again': 'Skontrolovať znova', 'dawarich.bucket.metersAway': '{meters} m ďaleko', 'dawarich.bucket.kilometersAway': '{km} km ďaleko', - 'dawarich.bucket.rule': 'Prianie sa počíta ako splnené do {meters} m a po {minutes} minútach na mieste.', + 'dawarich.bucket.rule': 'Prianie sa počíta ako splnené do {meters} m a po {count} minútach na mieste.', + 'dawarich.bucket.rule.one': 'Prianie sa počíta ako splnené do {meters} m a po {count} minúte na mieste.', + 'dawarich.bucket.rule.few': 'Prianie sa počíta ako splnené do {meters} m a po {count} minútach na mieste.', 'dawarich.journey.dayStays.other': '{count} pobytov z Dawarichu', 'dawarich.journey.dayStays.one': '{count} pobyt z Dawarichu', 'dawarich.journey.dayStays.few': '{count} pobyty z Dawarichu', diff --git a/shared/src/i18n/sk/roadtrip.ts b/shared/src/i18n/sk/roadtrip.ts index 1fa7daab2..7a4dcb3ba 100644 --- a/shared/src/i18n/sk/roadtrip.ts +++ b/shared/src/i18n/sk/roadtrip.ts @@ -54,7 +54,11 @@ const roadtrip: TranslationStrings = { 'roadtrip.window.conflict': 'Pevný čas je v rozpore s jazdou a dennými prestávkami. Ručné časy zostávajú nezmenené; automatické plánovanie je pozastavené.', 'roadtrip.window.tooLong': - 'Tieto časy cestovania by vyžadovali viac než {days} dní navyše. Zvoľte dlhšie denné okno.', + 'Tieto časy cestovania by vyžadovali viac než {count} dní navyše. Zvoľte dlhšie denné okno.', + 'roadtrip.window.tooLong.one': + 'Tieto časy cestovania by vyžadovali viac než {count} deň navyše. Zvoľte dlhšie denné okno.', + 'roadtrip.window.tooLong.few': + 'Tieto časy cestovania by vyžadovali viac než {count} dni navyše. Zvoľte dlhšie denné okno.', 'roadtrip.mode.roadtrip': 'Cesta autom', 'roadtrip.mode.days': 'Dni', 'roadtrip.mode.label': 'Zobrazenie plánu', @@ -102,8 +106,12 @@ const roadtrip: TranslationStrings = { 'roadtrip.limit.minutes': 'min', 'roadtrip.limit.off': 'vypnuté', 'roadtrip.limit.blockNote': 'Jeden blok = {distance}', - 'roadtrip.limit.echoOver': '{over} z {days} dní nad vaším limitom.', - 'roadtrip.limit.echoNone': 'Všetkých {days} dní je v rámci vašich limitov.', + 'roadtrip.limit.echoOver': '{over} z {count} dní nad vaším limitom.', + 'roadtrip.limit.echoOver.one': '{over} z {count} dňa nad vaším limitom.', + 'roadtrip.limit.echoOver.few': '{over} z {count} dní nad vaším limitom.', + 'roadtrip.limit.echoNone': 'Všetkých {count} dní je v rámci vašich limitov.', + 'roadtrip.limit.echoNone.one': 'Jediný deň je v rámci vašich limitov.', + 'roadtrip.limit.echoNone.few': 'Všetky {count} dni sú v rámci vašich limitov.', 'roadtrip.limit.echoDry': '{count} úsekov bez dosiahnuteľnej zastávky.', 'roadtrip.limit.echoDry.one': '{count} úsek bez dosiahnuteľnej zastávky.', 'roadtrip.limit.echoDry.few': '{count} úseky bez dosiahnuteľnej zastávky.', @@ -282,8 +290,12 @@ const roadtrip: TranslationStrings = { 'roadtrip.stop.computed': 'Vypočítané z jazdy', 'roadtrip.stop.endIsLeave': 'Na ceste autom sa v tomto čase odchádza.', 'roadtrip.via.hint': 'Potiahnutím zmeníte trasu, pravým tlačidlom odstránite', - 'roadtrip.warn.late': 'Príchod {minutes} min po čase, ktorý ste nastavili', - 'roadtrip.warn.missedLeave': 'Príchod {minutes} min po čase, ktorý ste nastavili na odchod', + 'roadtrip.warn.late': 'Príchod {count} min po čase, ktorý ste nastavili', + 'roadtrip.warn.late.one': 'Príchod {count} min po čase, ktorý ste nastavili', + 'roadtrip.warn.late.few': 'Príchod {count} min po čase, ktorý ste nastavili', + 'roadtrip.warn.missedLeave': 'Príchod {count} min po čase, ktorý ste nastavili na odchod', + 'roadtrip.warn.missedLeave.one': 'Príchod {count} min po čase, ktorý ste nastavili na odchod', + 'roadtrip.warn.missedLeave.few': 'Príchod {count} min po čase, ktorý ste nastavili na odchod', 'roadtrip.warn.overnight': 'Nasledujúci deň', 'roadtrip.spill.title': 'Zo dňa {number}', 'roadtrip.spill.departs': 'odchod {time}', diff --git a/shared/src/i18n/sk/settings.ts b/shared/src/i18n/sk/settings.ts index ed89ab6c2..8b5ac40d9 100644 --- a/shared/src/i18n/sk/settings.ts +++ b/shared/src/i18n/sk/settings.ts @@ -640,7 +640,11 @@ const settings: TranslationStrings = { 'settings.apiKeys.neverUsed': 'nikdy nepoužitý', 'settings.apiKeys.loadFailed': 'Vaše kľúče sa nepodarilo načítať. Obnovte stránku a skúste to znovu.', 'settings.apiKeys.limitReached': - 'Máte {max} kľúčov, čo je najviac, koľko účet môže mať. Zmažte niektorý, ktorý už nepoužívate, a vytvorte ďalší.', + 'Máte {count} kľúčov, čo je najviac, koľko účet môže mať. Zmažte niektorý, ktorý už nepoužívate, a vytvorte ďalší.', + 'settings.apiKeys.limitReached.one': + 'Máte {count} kľúč, čo je najviac, koľko účet môže mať. Zmažte ho, ak ho už nepoužívate, a vytvorte ďalší.', + 'settings.apiKeys.limitReached.few': + 'Máte {count} kľúče, čo je najviac, koľko účet môže mať. Zmažte niektorý, ktorý už nepoužívate, a vytvorte ďalší.', 'settings.apiKeys.copyFailed': 'Kopírovanie sa nepodarilo. Označte text a skopírujte ho ručne.', 'settings.apiKeys.modal.createTitle': 'Vytvoriť API kľúč', 'settings.apiKeys.modal.name': 'Názov', diff --git a/shared/src/i18n/sk/storage.ts b/shared/src/i18n/sk/storage.ts index 2eebd98d6..d2cc4d536 100644 --- a/shared/src/i18n/sk/storage.ts +++ b/shared/src/i18n/sk/storage.ts @@ -137,7 +137,9 @@ const storage: TranslationStrings = { // Category migration (copy → flip → delta sweep) 'storage.migrate.promptTitle': 'Presunúť existujúce objekty do nového backendu?', - 'storage.migrate.promptLine': '{category}: {objects} objektov ({size}) z {from} do {to}', + 'storage.migrate.promptLine': '{category}: {count} objektov ({size}) z {from} do {to}', + 'storage.migrate.promptLine.one': '{category}: {count} objekt ({size}) z {from} do {to}', + 'storage.migrate.promptLine.few': '{category}: {count} objekty ({size}) z {from} do {to}', 'storage.migrate.promptLineUnknown': '{category}: neznáma veľkosť (využitie ešte nebolo vypočítané) z {from} do {to}', 'storage.migrate.move': 'Presunúť existujúce objekty', 'storage.migrate.routeOnly': 'Iba smerovať nové zápisy', @@ -146,7 +148,9 @@ const storage: TranslationStrings = { 'storage.migrate.doneFailures': '{failed} zlyhalo — tieto objekty neboli skopírované do nového backendu', 'storage.migrate.failed': 'Presun zlyhal: {error} — kategória nebola prepnutá', 'storage.migrate.cancelled': 'Presun zrušený — nič nebolo prepnuté', - 'storage.migrate.reclaimable': '{objects} objektov ({size}) zostáva na {from} — uvoľnite ručne', + 'storage.migrate.reclaimable': '{count} objektov ({size}) zostáva na {from}, uvoľnite ručne', + 'storage.migrate.reclaimable.one': '{count} objekt ({size}) zostáva na {from}, uvoľnite ručne', + 'storage.migrate.reclaimable.few': '{count} objekty ({size}) zostávajú na {from}, uvoľnite ručne', 'storage.migrate.cancel': 'Zrušiť presun', 'storage.migrate.promptCancel': 'Zrušiť', 'storage.migrate.queued': 'V poradí: {categories}', diff --git a/shared/src/i18n/sv/collab.ts b/shared/src/i18n/sv/collab.ts index b316ffd27..efd0bb5c5 100644 --- a/shared/src/i18n/sv/collab.ts +++ b/shared/src/i18n/sv/collab.ts @@ -100,7 +100,8 @@ const collab: TranslationStrings = { 'collab.polls.options': 'Val', 'collab.polls.delete': 'Ta bort', 'collab.polls.closedSection': 'Stängd', - 'collab.chat.imageLimit': 'Du kan bifoga upp till {max} bilder per meddelande', + 'collab.chat.imageLimit': 'Du kan bifoga upp till {count} bilder per meddelande', + 'collab.chat.imageLimit.one': 'Du kan bifoga högst {count} bild per meddelande', 'collab.chat.uploading': 'Laddar upp {percent} %', 'collab.chat.attachImages': 'Bifoga bilder', 'collab.chat.attachedImage': 'Bifogad bild', diff --git a/shared/src/i18n/sv/dashboard.ts b/shared/src/i18n/sv/dashboard.ts index ae5232fb0..930a1206b 100644 --- a/shared/src/i18n/sv/dashboard.ts +++ b/shared/src/i18n/sv/dashboard.ts @@ -113,7 +113,8 @@ const dashboard: TranslationStrings = { 'dashboard.useUnsplashPhoto': 'Använd Unsplash-foto av {photographer}', 'dashboard.titleRequired': 'Titel är obligatoriskt', 'dashboard.endDateError': 'Slutdatumet måste ligga efter startdatumet', - 'dashboard.tripTooLong': 'En resa kan vara högst {days} dagar', + 'dashboard.tripTooLong': 'En resa kan vara högst {count} dagar', + 'dashboard.tripTooLong.one': 'En resa kan vara högst {count} dag', 'dashboard.dateShiftTitle': 'Nytt startdatum', 'dashboard.dateShiftIntro': 'Du har ändrat när resan börjar. Hur ska dina planer följa de nya datumen?', 'dashboard.dateShiftKeepBookings': 'Behåll bokningar på sina datum', diff --git a/shared/src/i18n/sv/dawarich.ts b/shared/src/i18n/sv/dawarich.ts index 72afa2b26..9596719eb 100644 --- a/shared/src/i18n/sv/dawarich.ts +++ b/shared/src/i18n/sv/dawarich.ts @@ -116,7 +116,8 @@ const dawarich: TranslationStrings = { 'dawarich.accept.confirm.journal': 'Lägg till inlägg', 'dawarich.accept.confirm.bucket_list': 'Bocka av den', 'dawarich.accept.recorded': 'Inspelad {from} till {to}', - 'dawarich.accept.duration': '{minutes} min', + 'dawarich.accept.duration': '{count} min', + 'dawarich.accept.duration.one': '{count} min', 'dawarich.accept.name': 'Namn', 'dawarich.accept.date': 'Datum', 'dawarich.accept.from': 'Ankom', @@ -181,7 +182,8 @@ const dawarich: TranslationStrings = { 'dawarich.again': 'Kontrollera igen', 'dawarich.bucket.metersAway': '{meters} m bort', 'dawarich.bucket.kilometersAway': '{km} km bort', - 'dawarich.bucket.rule': 'En önskning räknas som uppfylld inom {meters} m och efter {minutes} minuter på plats.', + 'dawarich.bucket.rule': 'En önskning räknas som uppfylld inom {meters} m och efter {count} minuter på plats.', + 'dawarich.bucket.rule.one': 'En önskning räknas som uppfylld inom {meters} m och efter {count} minut på plats.', 'dawarich.journey.dayStays.other': '{count} vistelser från Dawarich', 'dawarich.journey.dayStays.one': '{count} vistelse från Dawarich', diff --git a/shared/src/i18n/sv/roadtrip.ts b/shared/src/i18n/sv/roadtrip.ts index 71ac10e99..c3dc3e40f 100644 --- a/shared/src/i18n/sv/roadtrip.ts +++ b/shared/src/i18n/sv/roadtrip.ts @@ -54,7 +54,8 @@ const roadtrip: TranslationStrings = { 'roadtrip.window.incomplete': 'Alla anslutande rutter behövs för att beräkna dagliga pauser.', 'roadtrip.window.conflict': 'En fast tid krockar med körningen och pauserna. Manuella tider behålls; automatisk planering är pausad.', - 'roadtrip.window.tooLong': 'Dessa tider kräver fler än {days} extra dagar. Välj ett längre dagligt tidsintervall.', + 'roadtrip.window.tooLong': 'Dessa tider kräver fler än {count} extra dagar. Välj ett längre dagligt tidsintervall.', + 'roadtrip.window.tooLong.one': 'Dessa tider kräver mer än {count} extra dag. Välj ett längre dagligt tidsintervall.', 'roadtrip.mode.roadtrip': 'Bilresa', 'roadtrip.mode.days': 'Dagar', 'roadtrip.mode.label': 'Planvy', @@ -101,8 +102,10 @@ const roadtrip: TranslationStrings = { 'roadtrip.limit.minutes': 'min', 'roadtrip.limit.off': 'av', 'roadtrip.limit.blockNote': 'Ett block = {distance}', - 'roadtrip.limit.echoOver': '{over} av {days} dagar över din gräns.', - 'roadtrip.limit.echoNone': 'Alla {days} dagar inom dina gränser.', + 'roadtrip.limit.echoOver': '{over} av {count} dagar över din gräns.', + 'roadtrip.limit.echoOver.one': '{over} av {count} dag över din gräns.', + 'roadtrip.limit.echoNone': 'Alla {count} dagar inom dina gränser.', + 'roadtrip.limit.echoNone.one': 'Den enda dagen inom dina gränser.', 'roadtrip.limit.echoDry': '{count} sträckor utan nåbart stopp.', 'roadtrip.limit.echoDry.one': '{count} sträcka utan nåbart stopp.', 'roadtrip.limit.echoEmpty': 'Öppna en roadtrip för att se effekten.', @@ -270,8 +273,10 @@ const roadtrip: TranslationStrings = { 'roadtrip.stop.computed': 'Beräknad utifrån körningen', 'roadtrip.stop.endIsLeave': 'På bilresan åker ni vidare vid den här tiden.', 'roadtrip.via.hint': 'Dra för att forma om rutten, högerklicka för att ta bort', - 'roadtrip.warn.late': 'Ankomst {minutes} min efter den satta tiden', - 'roadtrip.warn.missedLeave': 'Ankomst {minutes} min efter den satta avfärdstiden', + 'roadtrip.warn.late': 'Ankomst {count} min efter den satta tiden', + 'roadtrip.warn.late.one': 'Ankomst {count} min efter den satta tiden', + 'roadtrip.warn.missedLeave': 'Ankomst {count} min efter den satta avfärdstiden', + 'roadtrip.warn.missedLeave.one': 'Ankomst {count} min efter den satta avfärdstiden', 'roadtrip.warn.overnight': 'Nästa dag', 'roadtrip.spill.title': 'Från dag {number}', 'roadtrip.spill.departs': 'avgång {time}', diff --git a/shared/src/i18n/sv/settings.ts b/shared/src/i18n/sv/settings.ts index facd91def..8ace59d55 100644 --- a/shared/src/i18n/sv/settings.ts +++ b/shared/src/i18n/sv/settings.ts @@ -626,7 +626,10 @@ const settings: TranslationStrings = { 'settings.apiKeys.endpoint': 'Ändpunkt', 'settings.apiKeys.neverUsed': 'aldrig använd', 'settings.apiKeys.loadFailed': 'Det gick inte att läsa in dina nycklar. Ladda om sidan för att försöka igen.', - 'settings.apiKeys.limitReached': 'Du har {max} nycklar, det högsta antalet per konto. Ta bort en som du inte längre använder för att skapa en ny.', + 'settings.apiKeys.limitReached': + 'Du har {count} nycklar, det högsta antalet per konto. Ta bort en som du inte längre använder för att skapa en ny.', + 'settings.apiKeys.limitReached.one': + 'Du har {count} nyckel, det högsta antalet per konto. Ta bort den om du inte längre använder den för att skapa en ny.', 'settings.apiKeys.copyFailed': 'Det gick inte att kopiera. Markera texten och kopiera den manuellt.', 'settings.apiKeys.modal.createTitle': 'Skapa API-nyckel', 'settings.apiKeys.modal.name': 'Namn', diff --git a/shared/src/i18n/sv/storage.ts b/shared/src/i18n/sv/storage.ts index 0fba58e5d..0954d1aaf 100644 --- a/shared/src/i18n/sv/storage.ts +++ b/shared/src/i18n/sv/storage.ts @@ -122,7 +122,8 @@ const storage: TranslationStrings = { // Category migration (copy → flip → delta sweep) 'storage.migrate.promptTitle': 'Flytta befintliga objekt till den nya backend?', - 'storage.migrate.promptLine': '{category}: {objects} objekt ({size}) från {from} till {to}', + 'storage.migrate.promptLine': '{category}: {count} objekt ({size}) från {from} till {to}', + 'storage.migrate.promptLine.one': '{category}: {count} objekt ({size}) från {from} till {to}', 'storage.migrate.promptLineUnknown': '{category}: okänd storlek (användning inte skannad än) från {from} till {to}', 'storage.migrate.move': 'Flytta befintliga objekt', 'storage.migrate.routeOnly': 'Dirigera bara nya skrivningar', @@ -131,7 +132,8 @@ const storage: TranslationStrings = { 'storage.migrate.doneFailures': '{failed} misslyckades — dessa objekt kopierades inte till den nya backend', 'storage.migrate.failed': 'Flytt misslyckades: {error} — kategorin byttes inte', 'storage.migrate.cancelled': 'Flytt avbruten — inget byttes', - 'storage.migrate.reclaimable': '{objects} objekt ({size}) finns kvar på {from} — återvinn manuellt', + 'storage.migrate.reclaimable': '{count} objekt ({size}) finns kvar på {from}, återvinn manuellt', + 'storage.migrate.reclaimable.one': '{count} objekt ({size}) finns kvar på {from}, återvinn manuellt', 'storage.migrate.cancel': 'Avbryt flytt', 'storage.migrate.promptCancel': 'Avbryt', 'storage.migrate.queued': 'I kö: {categories}', diff --git a/shared/src/i18n/th/collab.ts b/shared/src/i18n/th/collab.ts index 0d5076573..7cbd113f8 100644 --- a/shared/src/i18n/th/collab.ts +++ b/shared/src/i18n/th/collab.ts @@ -81,7 +81,7 @@ const collab: TranslationStrings = { 'collab.polls.options': 'ตัวเลือก', 'collab.polls.delete': 'ลบ', 'collab.polls.closedSection': 'ปิดแล้ว', - 'collab.chat.imageLimit': 'คุณแนบรูปภาพได้สูงสุด {max} รูปต่อข้อความ', + 'collab.chat.imageLimit': 'คุณแนบรูปภาพได้สูงสุด {count} รูปต่อข้อความ', 'collab.chat.uploading': 'กำลังอัปโหลด {percent}%', 'collab.chat.attachImages': 'แนบรูปภาพ', 'collab.chat.attachedImage': 'รูปภาพที่แนบ', diff --git a/shared/src/i18n/th/dashboard.ts b/shared/src/i18n/th/dashboard.ts index f2d6db7e4..94566fa9d 100644 --- a/shared/src/i18n/th/dashboard.ts +++ b/shared/src/i18n/th/dashboard.ts @@ -106,7 +106,7 @@ const dashboard: TranslationStrings = { 'dashboard.useUnsplashPhoto': 'ใช้รูปภาพ Unsplash โดย {photographer}', 'dashboard.titleRequired': 'ต้องระบุชื่อ', 'dashboard.endDateError': 'วันที่สิ้นสุดต้องอยู่หลังวันที่เริ่มต้น', - 'dashboard.tripTooLong': 'การเดินทางหนึ่งครั้งยาวได้สูงสุด {days} วัน', + 'dashboard.tripTooLong': 'การเดินทางหนึ่งครั้งยาวได้สูงสุด {count} วัน', 'dashboard.dateShiftTitle': 'วันที่เริ่มต้นใหม่', 'dashboard.dateShiftIntro': 'คุณเปลี่ยนวันที่เริ่มต้นของการเดินทางครั้งนี้ แผนของคุณควรปรับตามวันที่ใหม่อย่างไร', 'dashboard.dateShiftKeepBookings': 'ทำการจองตามวันที่ของพวกเขา', diff --git a/shared/src/i18n/th/dawarich.ts b/shared/src/i18n/th/dawarich.ts index c9c2517ef..39ffd2ebc 100644 --- a/shared/src/i18n/th/dawarich.ts +++ b/shared/src/i18n/th/dawarich.ts @@ -98,7 +98,7 @@ const dawarich: TranslationStrings = { 'dawarich.accept.confirm.journal': 'เพิ่มรายการ', 'dawarich.accept.confirm.bucket_list': 'ทำเครื่องหมายว่าสำเร็จ', 'dawarich.accept.recorded': 'บันทึกตั้งแต่ {from} ถึง {to}', - 'dawarich.accept.duration': '{minutes} นาที', + 'dawarich.accept.duration': '{count} นาที', 'dawarich.accept.name': 'ชื่อ', 'dawarich.accept.date': 'วันที่', 'dawarich.accept.from': 'มาถึง', @@ -149,7 +149,7 @@ const dawarich: TranslationStrings = { 'dawarich.again': 'ตรวจสอบอีกครั้ง', 'dawarich.bucket.metersAway': 'ห่าง {meters} ม.', 'dawarich.bucket.kilometersAway': 'ห่าง {km} กม.', - 'dawarich.bucket.rule': 'จะนับว่าไปถึงเมื่ออยู่ในระยะ {meters} ม. และอยู่ที่จุดนั้นอย่างน้อย {minutes} นาที', + 'dawarich.bucket.rule': 'จะนับว่าไปถึงเมื่ออยู่ในระยะ {meters} ม. และอยู่ที่จุดนั้นอย่างน้อย {count} นาที', 'dawarich.journey.dayStays.other': 'การพักจาก Dawarich {count} รายการ', }; diff --git a/shared/src/i18n/th/roadtrip.ts b/shared/src/i18n/th/roadtrip.ts index 2e6898389..116815900 100644 --- a/shared/src/i18n/th/roadtrip.ts +++ b/shared/src/i18n/th/roadtrip.ts @@ -52,7 +52,7 @@ const roadtrip: TranslationStrings = { 'roadtrip.window.incomplete': 'ยังคำนวณช่วงพักรายวันไม่ได้จนกว่าจะมีเส้นทางเชื่อมต่อครบ', 'roadtrip.window.conflict': 'เวลาที่กำหนดขัดกับการขับรถและช่วงพักรายวัน เวลาที่กำหนดเองจะไม่เปลี่ยน แต่การจัดตารางอัตโนมัติถูกพักไว้', - 'roadtrip.window.tooLong': 'เวลาเดินทางเหล่านี้จะต้องใช้วันเพิ่มมากกว่า {days} วัน เลือกกรอบเวลารายวันที่นานขึ้น', + 'roadtrip.window.tooLong': 'เวลาเดินทางเหล่านี้จะต้องใช้วันเพิ่มมากกว่า {count} วัน เลือกกรอบเวลารายวันที่นานขึ้น', 'roadtrip.mode.roadtrip': 'โรดทริป', 'roadtrip.mode.days': 'วัน', 'roadtrip.mode.label': 'มุมมองแผน', @@ -98,8 +98,8 @@ const roadtrip: TranslationStrings = { 'roadtrip.limit.minutes': 'นาที', 'roadtrip.limit.off': 'ปิด', 'roadtrip.limit.blockNote': 'หนึ่งช่วง = {distance}', - 'roadtrip.limit.echoOver': 'เกินขีดจำกัด {over} จาก {days} วัน', - 'roadtrip.limit.echoNone': 'ทั้ง {days} วันอยู่ในขีดจำกัด', + 'roadtrip.limit.echoOver': 'เกินขีดจำกัด {over} จาก {count} วัน', + 'roadtrip.limit.echoNone': 'ทั้ง {count} วันอยู่ในขีดจำกัด', 'roadtrip.limit.echoDry': 'มี {count} ช่วงที่ไม่มีจุดแวะที่ไปถึงได้', 'roadtrip.limit.echoEmpty': 'เปิดโรดทริปเพื่อดูผลของการตั้งค่าเหล่านี้', 'roadtrip.limit.specToggle': 'คำนวณจากข้อมูลรถ', @@ -249,8 +249,8 @@ const roadtrip: TranslationStrings = { 'roadtrip.stop.computed': 'คำนวณจากการขับรถ', 'roadtrip.stop.endIsLeave': 'ในโรดทริป รถจะออกเดินทางเวลานี้', 'roadtrip.via.hint': 'ลากเพื่อปรับเส้นทาง คลิกขวาเพื่อลบ', - 'roadtrip.warn.late': 'ถึงช้ากว่าเวลาที่กำหนด {minutes} นาที', - 'roadtrip.warn.missedLeave': 'ถึงช้ากว่าเวลาที่คุณตั้งไว้ว่าจะออก {minutes} นาที', + 'roadtrip.warn.late': 'ถึงช้ากว่าเวลาที่กำหนด {count} นาที', + 'roadtrip.warn.missedLeave': 'ถึงช้ากว่าเวลาที่คุณตั้งไว้ว่าจะออก {count} นาที', 'roadtrip.warn.overnight': 'วันถัดไป', 'roadtrip.spill.title': 'จากวันที่ {number}', 'roadtrip.spill.departs': 'ออกเวลา {time}', diff --git a/shared/src/i18n/th/settings.ts b/shared/src/i18n/th/settings.ts index 665c8f553..882156037 100644 --- a/shared/src/i18n/th/settings.ts +++ b/shared/src/i18n/th/settings.ts @@ -624,7 +624,7 @@ const settings: TranslationStrings = { 'settings.apiKeys.neverUsed': 'ไม่เคยใช้', 'settings.apiKeys.loadFailed': 'ไม่สามารถโหลดคีย์ของคุณได้ โหลดหน้านี้ใหม่เพื่อลองอีกครั้ง', 'settings.apiKeys.limitReached': - 'คุณมีคีย์ {max} อัน ซึ่งเป็นจำนวนสูงสุดที่บัญชีหนึ่งมีได้ ลบคีย์ที่ไม่ได้ใช้ออกเพื่อสร้างคีย์ใหม่', + 'คุณมีคีย์ {count} อัน ซึ่งเป็นจำนวนสูงสุดที่บัญชีหนึ่งมีได้ ลบคีย์ที่ไม่ได้ใช้ออกเพื่อสร้างคีย์ใหม่', 'settings.apiKeys.copyFailed': 'ไม่สามารถคัดลอกได้ เลือกข้อความและคัดลอกด้วยตนเอง', }; diff --git a/shared/src/i18n/th/storage.ts b/shared/src/i18n/th/storage.ts index a8782f3b3..a80320511 100644 --- a/shared/src/i18n/th/storage.ts +++ b/shared/src/i18n/th/storage.ts @@ -136,7 +136,7 @@ const storage: TranslationStrings = { // Category migration (copy → flip → delta sweep) 'storage.migrate.promptTitle': 'ย้ายวัตถุที่มีอยู่ไปยังแบ็กเอนด์ใหม่หรือไม่', - 'storage.migrate.promptLine': '{category}: {objects} วัตถุ ({size}) จาก {from} ถึง {to}', + 'storage.migrate.promptLine': '{category}: {count} วัตถุ ({size}) จาก {from} ถึง {to}', 'storage.migrate.promptLineUnknown': '{category}: ไม่ทราบขนาด (ยังไม่มีการสแกนการใช้งาน) จาก {from} ถึง {to}', 'storage.migrate.move': 'ย้ายวัตถุที่มีอยู่', 'storage.migrate.routeOnly': 'เพียงกำหนดเส้นทางการเขียนใหม่', @@ -145,7 +145,7 @@ const storage: TranslationStrings = { 'storage.migrate.doneFailures': '{failed} ล้มเหลว — ออบเจ็กต์เหล่านั้นไม่ได้ถูกคัดลอกไปยังแบ็กเอนด์ใหม่', 'storage.migrate.failed': 'การย้ายล้มเหลว: {error} — หมวดหมู่ไม่ได้ถูกเปลี่ยน', 'storage.migrate.cancelled': 'การย้ายถูกยกเลิก — ไม่มีอะไรถูกเปลี่ยน', - 'storage.migrate.reclaimable': 'วัตถุ {objects} ({size}) ยังคงอยู่บน {from} — เรียกคืนด้วยตนเอง', + 'storage.migrate.reclaimable': 'วัตถุ {count} ({size}) ยังคงอยู่บน {from} เรียกคืนด้วยตนเอง', 'storage.migrate.cancel': 'ยกเลิกการย้าย', 'storage.migrate.promptCancel': 'ยกเลิก', 'storage.migrate.queued': 'อยู่ในคิว: {categories}', diff --git a/shared/src/i18n/tr/collab.ts b/shared/src/i18n/tr/collab.ts index a88004db9..34f6e4023 100644 --- a/shared/src/i18n/tr/collab.ts +++ b/shared/src/i18n/tr/collab.ts @@ -100,7 +100,8 @@ const collab: TranslationStrings = { 'collab.polls.options': 'Seçenekler', 'collab.polls.delete': 'Sil', 'collab.polls.closedSection': 'Kapalı', - 'collab.chat.imageLimit': 'Her mesaja en fazla {max} görsel ekleyebilirsiniz', + 'collab.chat.imageLimit': 'Her mesaja en fazla {count} görsel ekleyebilirsiniz', + 'collab.chat.imageLimit.one': 'Her mesaja yalnızca {count} görsel ekleyebilirsiniz', 'collab.chat.uploading': 'Yükleniyor %{percent}', 'collab.chat.attachImages': 'Görsel ekle', 'collab.chat.attachedImage': 'Eklenen görsel', diff --git a/shared/src/i18n/tr/dashboard.ts b/shared/src/i18n/tr/dashboard.ts index f783aabe7..8ce328d66 100644 --- a/shared/src/i18n/tr/dashboard.ts +++ b/shared/src/i18n/tr/dashboard.ts @@ -113,7 +113,8 @@ const dashboard: TranslationStrings = { 'dashboard.useUnsplashPhoto': '{photographer} tarafından çekilen Unsplash fotoğrafını kullan', 'dashboard.titleRequired': 'Başlık gerekli', 'dashboard.endDateError': 'Bitiş tarihi başlangıçtan sonra olmalı', - 'dashboard.tripTooLong': 'Bir seyahat en fazla {days} gün sürebilir', + 'dashboard.tripTooLong': 'Bir seyahat en fazla {count} gün sürebilir', + 'dashboard.tripTooLong.one': 'Bir seyahat en fazla {count} gün sürebilir', 'dashboard.dateShiftTitle': 'Yeni başlangıç tarihi', 'dashboard.dateShiftIntro': 'Bu seyahatin başlangıç tarihini değiştirdiniz. Planlarınız yeni tarihlere nasıl uyum sağlasın?', diff --git a/shared/src/i18n/tr/dawarich.ts b/shared/src/i18n/tr/dawarich.ts index 6d8303622..5d2870a7a 100644 --- a/shared/src/i18n/tr/dawarich.ts +++ b/shared/src/i18n/tr/dawarich.ts @@ -119,7 +119,8 @@ const dawarich: TranslationStrings = { 'dawarich.accept.confirm.journal': 'Kayıt ekle', 'dawarich.accept.confirm.bucket_list': 'İşaretle', 'dawarich.accept.recorded': '{from} ile {to} arasında kaydedildi', - 'dawarich.accept.duration': '{minutes} dk', + 'dawarich.accept.duration': '{count} dk', + 'dawarich.accept.duration.one': '{count} dk', 'dawarich.accept.name': 'Ad', 'dawarich.accept.date': 'Tarih', 'dawarich.accept.from': 'Varış', @@ -184,7 +185,8 @@ const dawarich: TranslationStrings = { 'dawarich.again': 'Yeniden kontrol et', 'dawarich.bucket.metersAway': '{meters} m uzakta', 'dawarich.bucket.kilometersAway': '{km} km uzakta', - 'dawarich.bucket.rule': 'Bir dilek {meters} m yakınlıkta ve yerinde {minutes} dakika sonra ulaşılmış sayılır.', + 'dawarich.bucket.rule': 'Bir dilek {meters} m yakınlıkta ve yerinde {count} dakika sonra ulaşılmış sayılır.', + 'dawarich.bucket.rule.one': 'Bir dilek {meters} m yakınlıkta ve yerinde {count} dakika sonra ulaşılmış sayılır.', 'dawarich.journey.dayStays.other': 'Dawarich’ten {count} konaklama', 'dawarich.journey.dayStays.one': 'Dawarich’ten {count} konaklama', diff --git a/shared/src/i18n/tr/roadtrip.ts b/shared/src/i18n/tr/roadtrip.ts index df25d594a..4c0155088 100644 --- a/shared/src/i18n/tr/roadtrip.ts +++ b/shared/src/i18n/tr/roadtrip.ts @@ -56,7 +56,9 @@ const roadtrip: TranslationStrings = { 'roadtrip.window.incomplete': 'Günlük molaları hesaplamak için tüm bağlantı rotaları gereklidir.', 'roadtrip.window.conflict': 'Sabit bir saat sürüş ve molalarla çakışıyor. Elle girilen saatler korunur; otomatik planlama duraklatıldı.', - 'roadtrip.window.tooLong': 'Bu saatler {days} günden fazla ek süre gerektiriyor. Daha uzun bir günlük aralık seçin.', + 'roadtrip.window.tooLong': 'Bu saatler {count} günden fazla ek süre gerektiriyor. Daha uzun bir günlük aralık seçin.', + 'roadtrip.window.tooLong.one': + 'Bu saatler {count} günden fazla ek süre gerektiriyor. Daha uzun bir günlük aralık seçin.', 'roadtrip.mode.roadtrip': 'Yol gezisi', 'roadtrip.mode.days': 'Günler', 'roadtrip.mode.label': 'Plan görünümü', @@ -103,8 +105,10 @@ const roadtrip: TranslationStrings = { 'roadtrip.limit.minutes': 'dk', 'roadtrip.limit.off': 'kapalı', 'roadtrip.limit.blockNote': 'Bir blok = {distance}', - 'roadtrip.limit.echoOver': '{days} günün {over} tanesi sınırının üzerinde.', - 'roadtrip.limit.echoNone': '{days} günün tamamı sınırlar içinde.', + 'roadtrip.limit.echoOver': '{count} günün {over} tanesi sınırının üzerinde.', + 'roadtrip.limit.echoOver.one': '{count} günün {over} tanesi sınırının üzerinde.', + 'roadtrip.limit.echoNone': '{count} günün tamamı sınırlar içinde.', + 'roadtrip.limit.echoNone.one': 'Tek gün sınırlar içinde.', 'roadtrip.limit.echoDry': 'Ulaşılabilir durağı olmayan {count} kesim.', 'roadtrip.limit.echoDry.one': 'Ulaşılabilir durağı olmayan {count} kesim.', 'roadtrip.limit.echoEmpty': 'Etkiyi görmek için bir yol gezisi aç.', @@ -272,8 +276,10 @@ const roadtrip: TranslationStrings = { 'roadtrip.stop.computed': 'Sürüşe göre hesaplandı', 'roadtrip.stop.endIsLeave': 'Yol gezisinde bu saatte yola çıkılır.', 'roadtrip.via.hint': 'Rotayı yeniden şekillendirmek için sürükleyin, kaldırmak için sağ tıklayın', - 'roadtrip.warn.late': 'Belirlenen saatten {minutes} dk sonra varış', - 'roadtrip.warn.missedLeave': 'Belirlenen kalkış saatinden {minutes} dk sonra varış', + 'roadtrip.warn.late': 'Belirlenen saatten {count} dk sonra varış', + 'roadtrip.warn.late.one': 'Belirlenen saatten {count} dk sonra varış', + 'roadtrip.warn.missedLeave': 'Belirlenen kalkış saatinden {count} dk sonra varış', + 'roadtrip.warn.missedLeave.one': 'Belirlenen kalkış saatinden {count} dk sonra varış', 'roadtrip.warn.overnight': 'Ertesi gün', 'roadtrip.spill.title': '{number}. günden', 'roadtrip.spill.departs': 'kalkış {time}', diff --git a/shared/src/i18n/tr/settings.ts b/shared/src/i18n/tr/settings.ts index ee59f5b33..9a054a10c 100644 --- a/shared/src/i18n/tr/settings.ts +++ b/shared/src/i18n/tr/settings.ts @@ -629,7 +629,10 @@ const settings: TranslationStrings = { 'settings.apiKeys.endpoint': 'Uç nokta', 'settings.apiKeys.neverUsed': 'hiç kullanılmadı', 'settings.apiKeys.loadFailed': 'Anahtarların yüklenemedi. Tekrar denemek için sayfayı yenile.', - 'settings.apiKeys.limitReached': '{max} anahtarın var, bir hesap için üst sınır bu. Yeni bir anahtar oluşturmak için artık kullanmadığın birini sil.', + 'settings.apiKeys.limitReached': + '{count} anahtarın var, bir hesap için üst sınır bu. Yeni bir anahtar oluşturmak için artık kullanmadığın birini sil.', + 'settings.apiKeys.limitReached.one': + '{count} anahtarın var, bir hesap için üst sınır bu. Yeni bir anahtar oluşturmak için artık kullanmıyorsan onu sil.', 'settings.apiKeys.copyFailed': 'Kopyalanamadı. Metni seçip elle kopyala.', 'settings.apiKeys.modal.createTitle': 'API anahtarı oluştur', 'settings.apiKeys.modal.name': 'Ad', diff --git a/shared/src/i18n/tr/storage.ts b/shared/src/i18n/tr/storage.ts index 814d11d39..a457b6c11 100644 --- a/shared/src/i18n/tr/storage.ts +++ b/shared/src/i18n/tr/storage.ts @@ -123,7 +123,8 @@ const storage: TranslationStrings = { // Category migration (copy → flip → delta sweep) 'storage.migrate.promptTitle': 'Mevcut nesneler yeni arka uca taşınsın mı?', - 'storage.migrate.promptLine': '{category}: {from} konumundan {to} konumuna {objects} nesne ({size})', + 'storage.migrate.promptLine': '{category}: {from} konumundan {to} konumuna {count} nesne ({size})', + 'storage.migrate.promptLine.one': '{category}: {from} konumundan {to} konumuna {count} nesne ({size})', 'storage.migrate.promptLineUnknown': '{category}: bilinmeyen boyut (henüz kullanım taraması yapılmadı) {from} konumundan {to} konumuna', 'storage.migrate.move': 'Mevcut nesneleri taşı', @@ -133,7 +134,8 @@ const storage: TranslationStrings = { 'storage.migrate.doneFailures': '{failed} başarısız oldu — bu nesneler yeni arka uca kopyalanmadı', 'storage.migrate.failed': 'Taşıma başarısız oldu: {error} — kategori değiştirilmedi', 'storage.migrate.cancelled': 'Taşıma iptal edildi — hiçbir şey değiştirilmedi', - 'storage.migrate.reclaimable': '{objects} nesne ({size}) {from} üzerinde kalıyor — manuel olarak geri kazanın', + 'storage.migrate.reclaimable': '{count} nesne ({size}) {from} üzerinde kalıyor, manuel olarak geri kazanın', + 'storage.migrate.reclaimable.one': '{count} nesne ({size}) {from} üzerinde kalıyor, manuel olarak geri kazanın', 'storage.migrate.cancel': 'Taşımayı iptal et', 'storage.migrate.promptCancel': 'İptal', 'storage.migrate.queued': 'Sırada: {categories}', diff --git a/shared/src/i18n/uk/collab.ts b/shared/src/i18n/uk/collab.ts index 1d04753c1..4cf501179 100644 --- a/shared/src/i18n/uk/collab.ts +++ b/shared/src/i18n/uk/collab.ts @@ -108,7 +108,10 @@ const collab: TranslationStrings = { 'collab.polls.options': 'Варіанти', 'collab.polls.delete': 'Видалити', 'collab.polls.closedSection': 'Закриті', - 'collab.chat.imageLimit': 'До одного повідомлення можна додати до {max} зображень', + 'collab.chat.imageLimit': 'До одного повідомлення можна додати до {count} зображення', + 'collab.chat.imageLimit.one': 'До одного повідомлення можна додати до {count} зображення', + 'collab.chat.imageLimit.few': 'До одного повідомлення можна додати до {count} зображень', + 'collab.chat.imageLimit.many': 'До одного повідомлення можна додати до {count} зображень', 'collab.chat.uploading': 'Завантаження {percent}%', 'collab.chat.attachImages': 'Додати зображення', 'collab.chat.attachedImage': 'Додане зображення', diff --git a/shared/src/i18n/uk/dashboard.ts b/shared/src/i18n/uk/dashboard.ts index e1d98441c..6e023a585 100644 --- a/shared/src/i18n/uk/dashboard.ts +++ b/shared/src/i18n/uk/dashboard.ts @@ -129,7 +129,10 @@ const dashboard: TranslationStrings = { 'dashboard.useUnsplashPhoto': 'Використати фото Unsplash від {photographer}', 'dashboard.titleRequired': "Назва обов'язкова", 'dashboard.endDateError': 'Дата закінчення повинна бути пізніше дати початку', - 'dashboard.tripTooLong': 'Подорож може тривати не більше {days} днів', + 'dashboard.tripTooLong': 'Подорож може тривати не більше {count} дня', + 'dashboard.tripTooLong.one': 'Подорож може тривати не більше {count} дня', + 'dashboard.tripTooLong.few': 'Подорож може тривати не більше {count} днів', + 'dashboard.tripTooLong.many': 'Подорож може тривати не більше {count} днів', 'dashboard.dateShiftTitle': 'Нова дата початку', 'dashboard.dateShiftIntro': 'Ви змінили дату початку поїздки. Як ваші плани мають перейти на нові дати?', 'dashboard.dateShiftKeepBookings': 'Залишити бронювання на своїх датах', diff --git a/shared/src/i18n/uk/dawarich.ts b/shared/src/i18n/uk/dawarich.ts index 139a5d978..257f0c0ea 100644 --- a/shared/src/i18n/uk/dawarich.ts +++ b/shared/src/i18n/uk/dawarich.ts @@ -124,7 +124,10 @@ const dawarich: TranslationStrings = { 'dawarich.accept.confirm.journal': 'Додати запис', 'dawarich.accept.confirm.bucket_list': 'Позначити виконаним', 'dawarich.accept.recorded': 'Записано з {from} до {to}', - 'dawarich.accept.duration': '{minutes} хв', + 'dawarich.accept.duration': '{count} хв', + 'dawarich.accept.duration.one': '{count} хв', + 'dawarich.accept.duration.few': '{count} хв', + 'dawarich.accept.duration.many': '{count} хв', 'dawarich.accept.name': 'Назва', 'dawarich.accept.date': 'Дата', 'dawarich.accept.from': 'Прибуття', @@ -203,7 +206,10 @@ const dawarich: TranslationStrings = { 'dawarich.again': 'Перевірити знову', 'dawarich.bucket.metersAway': 'за {meters} м', 'dawarich.bucket.kilometersAway': 'за {km} км', - 'dawarich.bucket.rule': 'Бажання вважається здійсненим у межах {meters} м і після {minutes} хвилин на місці.', + 'dawarich.bucket.rule': 'Бажання вважається здійсненим у межах {meters} м і після {count} хвилини на місці.', + 'dawarich.bucket.rule.one': 'Бажання вважається здійсненим у межах {meters} м і після {count} хвилини на місці.', + 'dawarich.bucket.rule.few': 'Бажання вважається здійсненим у межах {meters} м і після {count} хвилин на місці.', + 'dawarich.bucket.rule.many': 'Бажання вважається здійсненим у межах {meters} м і після {count} хвилин на місці.', 'dawarich.journey.dayStays.other': '{count} перебування з Dawarich', 'dawarich.journey.dayStays.one': '{count} перебування з Dawarich', 'dawarich.journey.dayStays.few': '{count} перебування з Dawarich', diff --git a/shared/src/i18n/uk/roadtrip.ts b/shared/src/i18n/uk/roadtrip.ts index bd2208601..d6b84a9fb 100644 --- a/shared/src/i18n/uk/roadtrip.ts +++ b/shared/src/i18n/uk/roadtrip.ts @@ -55,7 +55,12 @@ const roadtrip: TranslationStrings = { 'roadtrip.window.incomplete': 'Для розрахунку щоденних перерв потрібні всі сполучні маршрути.', 'roadtrip.window.conflict': 'Фіксований час суперечить поїздці та перервам. Ручні значення збережено; автоматичне планування призупинено.', - 'roadtrip.window.tooLong': 'За цих налаштувань потрібно понад {days} додаткових днів. Збільште щоденний інтервал.', + 'roadtrip.window.tooLong': 'За цих налаштувань потрібно понад {count} додаткового дня. Збільште щоденний інтервал.', + 'roadtrip.window.tooLong.one': + 'За цих налаштувань потрібно понад {count} додатковий день. Збільште щоденний інтервал.', + 'roadtrip.window.tooLong.few': 'За цих налаштувань потрібно понад {count} додаткові дні. Збільште щоденний інтервал.', + 'roadtrip.window.tooLong.many': + 'За цих налаштувань потрібно понад {count} додаткових днів. Збільште щоденний інтервал.', 'roadtrip.mode.roadtrip': 'Автоподорож', 'roadtrip.mode.days': 'Дні', 'roadtrip.mode.label': 'Вигляд плану', @@ -104,8 +109,14 @@ const roadtrip: TranslationStrings = { 'roadtrip.limit.minutes': 'хв', 'roadtrip.limit.off': 'вимк', 'roadtrip.limit.blockNote': 'Один блок = {distance}', - 'roadtrip.limit.echoOver': '{over} із {days} днів понад твій ліміт.', - 'roadtrip.limit.echoNone': 'Усі {days} днів у межах лімітів.', + 'roadtrip.limit.echoOver': '{over} із {count} дня понад твій ліміт.', + 'roadtrip.limit.echoOver.one': '{over} із {count} дня понад твій ліміт.', + 'roadtrip.limit.echoOver.few': '{over} із {count} днів понад твій ліміт.', + 'roadtrip.limit.echoOver.many': '{over} із {count} днів понад твій ліміт.', + 'roadtrip.limit.echoNone': 'Усі {count} дня у межах лімітів.', + 'roadtrip.limit.echoNone.one': '{count} день у межах лімітів.', + 'roadtrip.limit.echoNone.few': 'Усі {count} дні у межах лімітів.', + 'roadtrip.limit.echoNone.many': 'Усі {count} днів у межах лімітів.', 'roadtrip.limit.echoDry': '{count} відрізка без досяжної зупинки.', 'roadtrip.limit.echoDry.one': '{count} відрізок без досяжної зупинки.', 'roadtrip.limit.echoDry.few': '{count} відрізки без досяжної зупинки.', @@ -297,8 +308,14 @@ const roadtrip: TranslationStrings = { 'roadtrip.stop.computed': 'Розраховано за часом у дорозі', 'roadtrip.stop.endIsLeave': 'В автоподорожі відʼїзд відбувається в цей час.', 'roadtrip.via.hint': 'Перетягніть, щоб змінити маршрут, права кнопка — видалити', - 'roadtrip.warn.late': 'Прибуття на {minutes} хв пізніше заданого часу', - 'roadtrip.warn.missedLeave': 'Прибуття на {minutes} хв пізніше заданого часу відʼїзду', + 'roadtrip.warn.late': 'Прибуття на {count} хв пізніше заданого часу', + 'roadtrip.warn.late.one': 'Прибуття на {count} хв пізніше заданого часу', + 'roadtrip.warn.late.few': 'Прибуття на {count} хв пізніше заданого часу', + 'roadtrip.warn.late.many': 'Прибуття на {count} хв пізніше заданого часу', + 'roadtrip.warn.missedLeave': 'Прибуття на {count} хв пізніше заданого часу відʼїзду', + 'roadtrip.warn.missedLeave.one': 'Прибуття на {count} хв пізніше заданого часу відʼїзду', + 'roadtrip.warn.missedLeave.few': 'Прибуття на {count} хв пізніше заданого часу відʼїзду', + 'roadtrip.warn.missedLeave.many': 'Прибуття на {count} хв пізніше заданого часу відʼїзду', 'roadtrip.warn.overnight': 'Наступний день', 'roadtrip.spill.title': 'З дня {number}', 'roadtrip.spill.departs': 'виїзд {time}', diff --git a/shared/src/i18n/uk/settings.ts b/shared/src/i18n/uk/settings.ts index ca2315ee4..e33b2af3b 100644 --- a/shared/src/i18n/uk/settings.ts +++ b/shared/src/i18n/uk/settings.ts @@ -644,7 +644,14 @@ const settings: TranslationStrings = { 'settings.apiKeys.endpoint': 'Ендпоінт', 'settings.apiKeys.neverUsed': 'не використовувався', 'settings.apiKeys.loadFailed': 'Не вдалося завантажити ключі. Оновіть сторінку, щоб спробувати ще раз.', - 'settings.apiKeys.limitReached': 'У вас {max} ключів, це максимум для одного облікового запису. Видаліть непотрібний ключ, щоб створити новий.', + 'settings.apiKeys.limitReached': + 'У вас {count} ключа, це максимум для одного облікового запису. Видаліть непотрібний ключ, щоб створити новий.', + 'settings.apiKeys.limitReached.one': + 'У вас {count} ключ, це максимум для одного облікового запису. Видаліть непотрібний ключ, щоб створити новий.', + 'settings.apiKeys.limitReached.few': + 'У вас {count} ключі, це максимум для одного облікового запису. Видаліть непотрібний ключ, щоб створити новий.', + 'settings.apiKeys.limitReached.many': + 'У вас {count} ключів, це максимум для одного облікового запису. Видаліть непотрібний ключ, щоб створити новий.', 'settings.apiKeys.copyFailed': 'Не вдалося скопіювати. Виділіть текст і скопіюйте його вручну.', 'settings.apiKeys.modal.createTitle': 'Створити ключ API', 'settings.apiKeys.modal.name': 'Назва', diff --git a/shared/src/i18n/uk/storage.ts b/shared/src/i18n/uk/storage.ts index 06ddbaed0..d0a4e0f07 100644 --- a/shared/src/i18n/uk/storage.ts +++ b/shared/src/i18n/uk/storage.ts @@ -126,7 +126,10 @@ const storage: TranslationStrings = { // Category migration (copy → flip → delta sweep) 'storage.migrate.promptTitle': "Перенести наявні об'єкти на новий бекенд?", - 'storage.migrate.promptLine': "{category}: {objects} об'єктів ({size}) з {from} до {to}", + 'storage.migrate.promptLine': "{category}: {count} об'єкта ({size}) з {from} до {to}", + 'storage.migrate.promptLine.one': "{category}: {count} об'єкт ({size}) з {from} до {to}", + 'storage.migrate.promptLine.few': "{category}: {count} об'єкти ({size}) з {from} до {to}", + 'storage.migrate.promptLine.many': "{category}: {count} об'єктів ({size}) з {from} до {to}", 'storage.migrate.promptLineUnknown': '{category}: невідомий розмір (використання ще не проскановано) з {from} до {to}', 'storage.migrate.move': "Перенести наявні об'єкти", @@ -136,7 +139,10 @@ const storage: TranslationStrings = { 'storage.migrate.doneFailures': "{failed} не вдалося — ці об'єкти не було скопійовано на новий бекенд", 'storage.migrate.failed': 'Перенесення не вдалося: {error} — категорію не перемкнуто', 'storage.migrate.cancelled': 'Перенесення скасовано — нічого не перемкнуто', - 'storage.migrate.reclaimable': "{objects} об'єктів ({size}) залишаються на {from} — звільніть вручну", + 'storage.migrate.reclaimable': "{count} об'єкта ({size}) залишаються на {from}, звільніть вручну", + 'storage.migrate.reclaimable.one': "{count} об'єкт ({size}) залишається на {from}, звільніть вручну", + 'storage.migrate.reclaimable.few': "{count} об'єкти ({size}) залишаються на {from}, звільніть вручну", + 'storage.migrate.reclaimable.many': "{count} об'єктів ({size}) залишаються на {from}, звільніть вручну", 'storage.migrate.cancel': 'Скасувати перенесення', 'storage.migrate.promptCancel': 'Скасувати', 'storage.migrate.queued': 'У черзі: {categories}', diff --git a/shared/src/i18n/vi/collab.ts b/shared/src/i18n/vi/collab.ts index 75bbdce47..ae7a3cc3a 100644 --- a/shared/src/i18n/vi/collab.ts +++ b/shared/src/i18n/vi/collab.ts @@ -96,7 +96,7 @@ const collab: TranslationStrings = { 'collab.polls.options': 'Tùy chọn', 'collab.polls.delete': 'Xóa bỏ', 'collab.polls.closedSection': 'Đã đóng', - 'collab.chat.imageLimit': 'Bạn có thể đính kèm tối đa {max} ảnh cho mỗi tin nhắn', + 'collab.chat.imageLimit': 'Bạn có thể đính kèm tối đa {count} ảnh cho mỗi tin nhắn', 'collab.chat.uploading': 'Đang tải lên {percent}%', 'collab.chat.attachImages': 'Đính kèm ảnh', 'collab.chat.attachedImage': 'Ảnh đính kèm', diff --git a/shared/src/i18n/vi/dashboard.ts b/shared/src/i18n/vi/dashboard.ts index f35f02fbf..039da08b3 100644 --- a/shared/src/i18n/vi/dashboard.ts +++ b/shared/src/i18n/vi/dashboard.ts @@ -100,7 +100,7 @@ const dashboard: TranslationStrings = { 'dashboard.coverRemoveError': 'Không thể xóa', 'dashboard.titleRequired': 'Tiêu đề là bắt buộc', 'dashboard.endDateError': 'Ngày kết thúc phải sau ngày bắt đầu', - 'dashboard.tripTooLong': 'Một chuyến đi có thể kéo dài tối đa {days} ngày', + 'dashboard.tripTooLong': 'Một chuyến đi có thể kéo dài tối đa {count} ngày', 'dashboard.dateShiftTitle': 'Ngày bắt đầu mới', 'dashboard.dateShiftIntro': 'Bạn đã thay đổi thời điểm bắt đầu chuyến đi. Các kế hoạch của bạn nên theo ngày mới như thế nào?', diff --git a/shared/src/i18n/vi/dawarich.ts b/shared/src/i18n/vi/dawarich.ts index 801013b6b..db7615860 100644 --- a/shared/src/i18n/vi/dawarich.ts +++ b/shared/src/i18n/vi/dawarich.ts @@ -112,7 +112,7 @@ const dawarich: TranslationStrings = { 'dawarich.accept.confirm.journal': 'Thêm mục nhập', 'dawarich.accept.confirm.bucket_list': 'Đánh dấu hoàn thành', 'dawarich.accept.recorded': 'Được ghi từ {from} đến {to}', - 'dawarich.accept.duration': '{minutes} phút', + 'dawarich.accept.duration': '{count} phút', 'dawarich.accept.name': 'Tên', 'dawarich.accept.date': 'Ngày', 'dawarich.accept.from': 'Đến nơi', @@ -170,7 +170,7 @@ const dawarich: TranslationStrings = { 'dawarich.again': 'Kiểm tra lại', 'dawarich.bucket.metersAway': 'cách {meters} m', 'dawarich.bucket.kilometersAway': 'cách {km} km', - 'dawarich.bucket.rule': 'Một điều ước được tính là đã đến khi trong vòng {meters} m và sau {minutes} phút tại chỗ.', + 'dawarich.bucket.rule': 'Một điều ước được tính là đã đến khi trong vòng {meters} m và sau {count} phút tại chỗ.', 'dawarich.journey.dayStays.other': '{count} điểm lưu trú từ Dawarich', }; diff --git a/shared/src/i18n/vi/roadtrip.ts b/shared/src/i18n/vi/roadtrip.ts index 35b5741bc..f84dcef73 100644 --- a/shared/src/i18n/vi/roadtrip.ts +++ b/shared/src/i18n/vi/roadtrip.ts @@ -55,7 +55,7 @@ const roadtrip: TranslationStrings = { 'roadtrip.window.incomplete': 'Cần có tất cả tuyến đường nối để tính thời gian nghỉ hằng ngày.', 'roadtrip.window.conflict': 'Một giờ cố định xung đột với việc lái xe và nghỉ. Giờ thủ công được giữ nguyên; lập lịch tự động tạm dừng.', - 'roadtrip.window.tooLong': 'Các giờ này cần hơn {days} ngày bổ sung. Hãy chọn khoảng thời gian mỗi ngày dài hơn.', + 'roadtrip.window.tooLong': 'Các giờ này cần hơn {count} ngày bổ sung. Hãy chọn khoảng thời gian mỗi ngày dài hơn.', 'roadtrip.mode.roadtrip': 'Chuyến đi đường bộ', 'roadtrip.mode.days': 'Ngày', 'roadtrip.mode.label': 'Chế độ xem kế hoạch', @@ -101,8 +101,8 @@ const roadtrip: TranslationStrings = { 'roadtrip.limit.minutes': 'phút', 'roadtrip.limit.off': 'tắt', 'roadtrip.limit.blockNote': 'Một khối = {distance}', - 'roadtrip.limit.echoOver': '{over} trong {days} ngày vượt giới hạn.', - 'roadtrip.limit.echoNone': 'Cả {days} ngày đều trong giới hạn.', + 'roadtrip.limit.echoOver': '{over} trong {count} ngày vượt giới hạn.', + 'roadtrip.limit.echoNone': 'Cả {count} ngày đều trong giới hạn.', 'roadtrip.limit.echoDry': '{count} đoạn không có điểm dừng trong tầm với.', 'roadtrip.limit.echoEmpty': 'Mở một chuyến road trip để thấy tác dụng.', 'roadtrip.limit.specToggle': 'Tính từ thông số xe', @@ -260,8 +260,8 @@ const roadtrip: TranslationStrings = { 'roadtrip.stop.computed': 'Tính từ thời gian lái xe', 'roadtrip.stop.endIsLeave': 'Trong chuyến đi đường bộ, sẽ khởi hành vào giờ này.', 'roadtrip.via.hint': 'Kéo để định hình lại lộ trình, chuột phải để xóa', - 'roadtrip.warn.late': 'Đến muộn {minutes} phút so với giờ đã đặt', - 'roadtrip.warn.missedLeave': 'Đến muộn {minutes} phút so với giờ rời đi đã đặt', + 'roadtrip.warn.late': 'Đến muộn {count} phút so với giờ đã đặt', + 'roadtrip.warn.missedLeave': 'Đến muộn {count} phút so với giờ rời đi đã đặt', 'roadtrip.warn.overnight': 'Ngày hôm sau', 'roadtrip.spill.title': 'Từ ngày {number}', 'roadtrip.spill.departs': 'khởi hành {time}', diff --git a/shared/src/i18n/vi/settings.ts b/shared/src/i18n/vi/settings.ts index f1a430b1f..36e1a2228 100644 --- a/shared/src/i18n/vi/settings.ts +++ b/shared/src/i18n/vi/settings.ts @@ -624,7 +624,8 @@ const settings: TranslationStrings = { 'settings.apiKeys.endpoint': 'Điểm cuối', 'settings.apiKeys.neverUsed': 'chưa từng dùng', 'settings.apiKeys.loadFailed': 'Không thể tải các khóa của bạn. Hãy tải lại trang để thử lại.', - 'settings.apiKeys.limitReached': 'Bạn đã có {max} khóa, mức tối đa cho một tài khoản. Hãy xóa một khóa không còn dùng để tạo khóa mới.', + 'settings.apiKeys.limitReached': + 'Bạn đã có {count} khóa, mức tối đa cho một tài khoản. Hãy xóa một khóa không còn dùng để tạo khóa mới.', 'settings.apiKeys.copyFailed': 'Không thể sao chép. Hãy chọn đoạn văn bản và sao chép thủ công.', 'settings.apiKeys.modal.createTitle': 'Tạo khóa API', 'settings.apiKeys.modal.name': 'Tên', diff --git a/shared/src/i18n/vi/storage.ts b/shared/src/i18n/vi/storage.ts index 149b7079f..aef26531c 100644 --- a/shared/src/i18n/vi/storage.ts +++ b/shared/src/i18n/vi/storage.ts @@ -122,7 +122,7 @@ const storage: TranslationStrings = { // Category migration (copy → flip → delta sweep) 'storage.migrate.promptTitle': 'Di chuyển các đối tượng hiện có sang backend mới?', - 'storage.migrate.promptLine': '{category}: {objects} đối tượng ({size}) từ {from} sang {to}', + 'storage.migrate.promptLine': '{category}: {count} đối tượng ({size}) từ {from} sang {to}', 'storage.migrate.promptLineUnknown': '{category}: không rõ dung lượng (chưa quét mức sử dụng) từ {from} sang {to}', 'storage.migrate.move': 'Di chuyển các đối tượng hiện có', 'storage.migrate.routeOnly': 'Chỉ định tuyến các ghi mới', @@ -131,7 +131,7 @@ const storage: TranslationStrings = { 'storage.migrate.doneFailures': '{failed} thất bại — các đối tượng đó chưa được sao chép sang backend mới', 'storage.migrate.failed': 'Di chuyển thất bại: {error} — danh mục chưa được chuyển đổi', 'storage.migrate.cancelled': 'Đã hủy di chuyển — chưa có gì được chuyển đổi', - 'storage.migrate.reclaimable': '{objects} đối tượng ({size}) vẫn còn trên {from} — hãy thu hồi thủ công', + 'storage.migrate.reclaimable': '{count} đối tượng ({size}) vẫn còn trên {from}, hãy thu hồi thủ công', 'storage.migrate.cancel': 'Hủy di chuyển', 'storage.migrate.promptCancel': 'Hủy', 'storage.migrate.queued': 'Đang chờ: {categories}', diff --git a/shared/src/i18n/zh-TW/collab.ts b/shared/src/i18n/zh-TW/collab.ts index f2aec4e45..c17e4b434 100644 --- a/shared/src/i18n/zh-TW/collab.ts +++ b/shared/src/i18n/zh-TW/collab.ts @@ -96,7 +96,7 @@ const collab: TranslationStrings = { 'collab.polls.options': '選項', 'collab.polls.delete': '刪除', 'collab.polls.closedSection': '已關閉', - 'collab.chat.imageLimit': '每則訊息最多可附加 {max} 張圖片', + 'collab.chat.imageLimit': '每則訊息最多可附加 {count} 張圖片', 'collab.chat.uploading': '上傳中 {percent}%', 'collab.chat.attachImages': '附加圖片', 'collab.chat.attachedImage': '附加的圖片', diff --git a/shared/src/i18n/zh-TW/dashboard.ts b/shared/src/i18n/zh-TW/dashboard.ts index ca9832f17..bd349b8a7 100644 --- a/shared/src/i18n/zh-TW/dashboard.ts +++ b/shared/src/i18n/zh-TW/dashboard.ts @@ -92,7 +92,7 @@ const dashboard: TranslationStrings = { 'dashboard.useUnsplashPhoto': '使用 {photographer} 的 Unsplash 照片', 'dashboard.titleRequired': '標題為必填項', 'dashboard.endDateError': '結束日期必須晚於開始日期', - 'dashboard.tripTooLong': '行程最長為 {days} 天', + 'dashboard.tripTooLong': '行程最長為 {count} 天', 'dashboard.dateShiftTitle': '新的開始日期', 'dashboard.dateShiftIntro': '你變更了旅行的開始時間。你的計劃要如何配合新日期?', 'dashboard.dateShiftKeepBookings': '預訂保留在原日期', diff --git a/shared/src/i18n/zh-TW/dawarich.ts b/shared/src/i18n/zh-TW/dawarich.ts index 46c96c942..e4af0370b 100644 --- a/shared/src/i18n/zh-TW/dawarich.ts +++ b/shared/src/i18n/zh-TW/dawarich.ts @@ -112,7 +112,7 @@ const dawarich: TranslationStrings = { 'dawarich.accept.confirm.journal': '新增條目', 'dawarich.accept.confirm.bucket_list': '打勾', 'dawarich.accept.recorded': '記錄時間 {from} 至 {to}', - 'dawarich.accept.duration': '{minutes} 分鐘', + 'dawarich.accept.duration': '{count} 分鐘', 'dawarich.accept.name': '名稱', 'dawarich.accept.date': '日期', 'dawarich.accept.from': '抵達', @@ -170,7 +170,7 @@ const dawarich: TranslationStrings = { 'dawarich.again': '再查一次', 'dawarich.bucket.metersAway': '{meters} 公尺外', 'dawarich.bucket.kilometersAway': '{km} 公里外', - 'dawarich.bucket.rule': '在 {meters} 公尺內停留 {minutes} 分鐘以上,才算實現心願。', + 'dawarich.bucket.rule': '在 {meters} 公尺內停留 {count} 分鐘以上,才算實現心願。', 'dawarich.journey.dayStays.other': '來自 Dawarich 的 {count} 個停留點', }; diff --git a/shared/src/i18n/zh-TW/roadtrip.ts b/shared/src/i18n/zh-TW/roadtrip.ts index d37e5433b..3450e7cf9 100644 --- a/shared/src/i18n/zh-TW/roadtrip.ts +++ b/shared/src/i18n/zh-TW/roadtrip.ts @@ -49,7 +49,7 @@ const roadtrip: TranslationStrings = { 'roadtrip.window.showPoint': '在地圖上顯示', 'roadtrip.window.incomplete': '所有連接路線可用後才能計算每日休息。', 'roadtrip.window.conflict': '固定時間與行車和休息安排衝突。手動時間保持不變,自動規劃已暫停。', - 'roadtrip.window.tooLong': '這些時間需要超過{days}個額外天數。請延長每日出行時段。', + 'roadtrip.window.tooLong': '這些時間需要超過{count}個額外天數。請延長每日出行時段。', 'roadtrip.mode.roadtrip': '公路旅行', 'roadtrip.mode.days': '依日', 'roadtrip.mode.label': '計畫檢視', @@ -95,8 +95,8 @@ const roadtrip: TranslationStrings = { 'roadtrip.limit.minutes': '分鐘', 'roadtrip.limit.off': '關閉', 'roadtrip.limit.blockNote': '一格 = {distance}', - 'roadtrip.limit.echoOver': '{days} 天中有 {over} 天超出上限。', - 'roadtrip.limit.echoNone': '{days} 天都在上限之內。', + 'roadtrip.limit.echoOver': '{count} 天中有 {over} 天超出上限。', + 'roadtrip.limit.echoNone': '{count} 天都在上限之內。', 'roadtrip.limit.echoDry': '{count} 個路段沒有可抵達的停靠點。', 'roadtrip.limit.echoEmpty': '開啟一次公路旅行即可看到效果。', 'roadtrip.limit.specToggle': '依車輛資料推算', @@ -244,8 +244,8 @@ const roadtrip: TranslationStrings = { 'roadtrip.stop.computed': '依行駛時間推算', 'roadtrip.stop.endIsLeave': '在公路旅行中,將在此時間出發。', 'roadtrip.via.hint': '拖曳可改變路線,右鍵刪除', - 'roadtrip.warn.late': '比設定時間晚到 {minutes} 分鐘', - 'roadtrip.warn.missedLeave': '比設定的出發時間晚到 {minutes} 分鐘', + 'roadtrip.warn.late': '比設定時間晚到 {count} 分鐘', + 'roadtrip.warn.missedLeave': '比設定的出發時間晚到 {count} 分鐘', 'roadtrip.warn.overnight': '次日', 'roadtrip.spill.title': '來自第 {number} 天', 'roadtrip.spill.departs': '{time} 出發', diff --git a/shared/src/i18n/zh-TW/settings.ts b/shared/src/i18n/zh-TW/settings.ts index a80e05b53..e884fac3d 100644 --- a/shared/src/i18n/zh-TW/settings.ts +++ b/shared/src/i18n/zh-TW/settings.ts @@ -584,7 +584,7 @@ const settings: TranslationStrings = { 'settings.apiKeys.endpoint': '端點', 'settings.apiKeys.neverUsed': '從未使用', 'settings.apiKeys.loadFailed': '無法載入你的金鑰。請重新整理頁面後再試一次。', - 'settings.apiKeys.limitReached': '你已有 {max} 組金鑰,已達每個帳號的上限。請刪除一組不再使用的金鑰後再建立。', + 'settings.apiKeys.limitReached': '你已有 {count} 組金鑰,已達每個帳號的上限。請刪除一組不再使用的金鑰後再建立。', 'settings.apiKeys.copyFailed': '無法複製。請選取文字後手動複製。', 'settings.apiKeys.modal.createTitle': '建立 API 金鑰', 'settings.apiKeys.modal.name': '名稱', diff --git a/shared/src/i18n/zh-TW/storage.ts b/shared/src/i18n/zh-TW/storage.ts index 5b730ab12..5887ac87a 100644 --- a/shared/src/i18n/zh-TW/storage.ts +++ b/shared/src/i18n/zh-TW/storage.ts @@ -112,7 +112,7 @@ const storage: TranslationStrings = { // Category migration (copy → flip → delta sweep) 'storage.migrate.promptTitle': '要將現有物件移動到新的後端嗎?', - 'storage.migrate.promptLine': '{category}:從 {from} 到 {to} 共 {objects} 個物件({size})', + 'storage.migrate.promptLine': '{category}:從 {from} 到 {to} 共 {count} 個物件({size})', 'storage.migrate.promptLineUnknown': '{category}:大小未知(尚未掃描用量)從 {from} 到 {to}', 'storage.migrate.move': '移動現有物件', 'storage.migrate.routeOnly': '僅路由新寫入', @@ -121,7 +121,7 @@ const storage: TranslationStrings = { 'storage.migrate.doneFailures': '{failed} 個失敗 — 這些物件未複製到新的後端', 'storage.migrate.failed': '移動失敗:{error} — 該分類未切換', 'storage.migrate.cancelled': '移動已取消 — 未切換任何內容', - 'storage.migrate.reclaimable': '{objects} 個物件({size})仍保留在 {from} 上 — 請手動回收', + 'storage.migrate.reclaimable': '{count} 個物件({size})仍保留在 {from} 上,請手動回收', 'storage.migrate.cancel': '取消移動', 'storage.migrate.promptCancel': '取消', 'storage.migrate.queued': '排隊中:{categories}', diff --git a/shared/src/i18n/zh/collab.ts b/shared/src/i18n/zh/collab.ts index 5edba8643..a82fa9dc0 100644 --- a/shared/src/i18n/zh/collab.ts +++ b/shared/src/i18n/zh/collab.ts @@ -96,7 +96,7 @@ const collab: TranslationStrings = { 'collab.polls.options': '选项', 'collab.polls.delete': '删除', 'collab.polls.closedSection': '已关闭', - 'collab.chat.imageLimit': '每条消息最多可附加 {max} 张图片', + 'collab.chat.imageLimit': '每条消息最多可附加 {count} 张图片', 'collab.chat.uploading': '上传中 {percent}%', 'collab.chat.attachImages': '附加图片', 'collab.chat.attachedImage': '附加的图片', diff --git a/shared/src/i18n/zh/dashboard.ts b/shared/src/i18n/zh/dashboard.ts index e518e562d..438bcfdeb 100644 --- a/shared/src/i18n/zh/dashboard.ts +++ b/shared/src/i18n/zh/dashboard.ts @@ -92,7 +92,7 @@ const dashboard: TranslationStrings = { 'dashboard.useUnsplashPhoto': '使用 {photographer} 的 Unsplash 照片', 'dashboard.titleRequired': '标题为必填项', 'dashboard.endDateError': '结束日期必须晚于开始日期', - 'dashboard.tripTooLong': '行程最长为 {days} 天', + 'dashboard.tripTooLong': '行程最长为 {count} 天', 'dashboard.dateShiftTitle': '新的开始日期', 'dashboard.dateShiftIntro': '您更改了旅行的开始时间。您的计划应如何适应新的日期?', 'dashboard.dateShiftKeepBookings': '保留预订的原定日期', diff --git a/shared/src/i18n/zh/dawarich.ts b/shared/src/i18n/zh/dawarich.ts index b892da5e5..83ce4c584 100644 --- a/shared/src/i18n/zh/dawarich.ts +++ b/shared/src/i18n/zh/dawarich.ts @@ -112,7 +112,7 @@ const dawarich: TranslationStrings = { 'dawarich.accept.confirm.journal': '添加条目', 'dawarich.accept.confirm.bucket_list': '勾掉它', 'dawarich.accept.recorded': '记录时间:{from} 至 {to}', - 'dawarich.accept.duration': '{minutes} 分钟', + 'dawarich.accept.duration': '{count} 分钟', 'dawarich.accept.name': '名称', 'dawarich.accept.date': '日期', 'dawarich.accept.from': '到达', @@ -170,7 +170,7 @@ const dawarich: TranslationStrings = { 'dawarich.again': '再查一次', 'dawarich.bucket.metersAway': '{meters} 米外', 'dawarich.bucket.kilometersAway': '{km} 公里外', - 'dawarich.bucket.rule': '在 {meters} 米以内停留 {minutes} 分钟以上,才算实现心愿。', + 'dawarich.bucket.rule': '在 {meters} 米以内停留 {count} 分钟以上,才算实现心愿。', 'dawarich.journey.dayStays.other': '来自 Dawarich 的 {count} 条停留记录', }; diff --git a/shared/src/i18n/zh/roadtrip.ts b/shared/src/i18n/zh/roadtrip.ts index f38a5b47c..9cbafe138 100644 --- a/shared/src/i18n/zh/roadtrip.ts +++ b/shared/src/i18n/zh/roadtrip.ts @@ -49,7 +49,7 @@ const roadtrip: TranslationStrings = { 'roadtrip.window.showPoint': '在地图上显示', 'roadtrip.window.incomplete': '所有连接路线可用后才能计算每日休息。', 'roadtrip.window.conflict': '固定时间与行车和休息安排冲突。手动时间保持不变,自动规划已暂停。', - 'roadtrip.window.tooLong': '这些时间需要超过{days}个额外天数。请延长每日出行时段。', + 'roadtrip.window.tooLong': '这些时间需要超过{count}个额外天数。请延长每日出行时段。', 'roadtrip.mode.roadtrip': '公路旅行', 'roadtrip.mode.days': '按天', 'roadtrip.mode.label': '计划视图', @@ -95,8 +95,8 @@ const roadtrip: TranslationStrings = { 'roadtrip.limit.minutes': '分钟', 'roadtrip.limit.off': '关闭', 'roadtrip.limit.blockNote': '一格 = {distance}', - 'roadtrip.limit.echoOver': '{days} 天中有 {over} 天超出上限。', - 'roadtrip.limit.echoNone': '{days} 天都在上限之内。', + 'roadtrip.limit.echoOver': '{count} 天中有 {over} 天超出上限。', + 'roadtrip.limit.echoNone': '{count} 天都在上限之内。', 'roadtrip.limit.echoDry': '{count} 个路段没有可到达的停留点。', 'roadtrip.limit.echoEmpty': '打开一次公路旅行即可看到效果。', 'roadtrip.limit.specToggle': '根据车辆数据推算', @@ -245,8 +245,8 @@ const roadtrip: TranslationStrings = { 'roadtrip.stop.computed': '根据行驶时间推算', 'roadtrip.stop.endIsLeave': '在公路旅行中,将在此时间出发。', 'roadtrip.via.hint': '拖动可改变路线,右键删除', - 'roadtrip.warn.late': '比设定时间晚到 {minutes} 分钟', - 'roadtrip.warn.missedLeave': '比设定的出发时间晚到 {minutes} 分钟', + 'roadtrip.warn.late': '比设定时间晚到 {count} 分钟', + 'roadtrip.warn.missedLeave': '比设定的出发时间晚到 {count} 分钟', 'roadtrip.warn.overnight': '次日', 'roadtrip.spill.title': '来自第 {number} 天', 'roadtrip.spill.departs': '{time} 出发', diff --git a/shared/src/i18n/zh/settings.ts b/shared/src/i18n/zh/settings.ts index 0d52e00fb..12d0b1df1 100644 --- a/shared/src/i18n/zh/settings.ts +++ b/shared/src/i18n/zh/settings.ts @@ -580,7 +580,7 @@ const settings: TranslationStrings = { 'settings.apiKeys.endpoint': '端点', 'settings.apiKeys.neverUsed': '从未使用', 'settings.apiKeys.loadFailed': '无法加载你的密钥。请刷新页面后重试。', - 'settings.apiKeys.limitReached': '你已有 {max} 个密钥,已达到每个账户的上限。请删除一个不再使用的密钥后再创建。', + 'settings.apiKeys.limitReached': '你已有 {count} 个密钥,已达到每个账户的上限。请删除一个不再使用的密钥后再创建。', 'settings.apiKeys.copyFailed': '无法复制。请选中文本后手动复制。', 'settings.apiKeys.modal.createTitle': '创建 API 密钥', 'settings.apiKeys.modal.name': '名称', diff --git a/shared/src/i18n/zh/storage.ts b/shared/src/i18n/zh/storage.ts index 2b66c0b55..eb838cc61 100644 --- a/shared/src/i18n/zh/storage.ts +++ b/shared/src/i18n/zh/storage.ts @@ -111,7 +111,7 @@ const storage: TranslationStrings = { // Category migration (copy → flip → delta sweep) 'storage.migrate.promptTitle': '将现有对象移动到新后端?', - 'storage.migrate.promptLine': '{category}:从 {from} 到 {to} 共 {objects} 个对象({size})', + 'storage.migrate.promptLine': '{category}:从 {from} 到 {to} 共 {count} 个对象({size})', 'storage.migrate.promptLineUnknown': '{category}:大小未知(尚未扫描用量)从 {from} 到 {to}', 'storage.migrate.move': '移动现有对象', 'storage.migrate.routeOnly': '仅路由新写入', @@ -120,7 +120,7 @@ const storage: TranslationStrings = { 'storage.migrate.doneFailures': '{failed} 个失败 — 这些对象未复制到新后端', 'storage.migrate.failed': '移动失败:{error} — 该分类未切换', 'storage.migrate.cancelled': '移动已取消 — 未切换任何内容', - 'storage.migrate.reclaimable': '{objects} 个对象({size})仍保留在 {from} 上 — 请手动回收', + 'storage.migrate.reclaimable': '{count} 个对象({size})仍保留在 {from} 上,请手动回收', 'storage.migrate.cancel': '取消移动', 'storage.migrate.promptCancel': '取消', 'storage.migrate.queued': '排队中:{categories}',