mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-23 07:26:30 +00:00
fix(journey): the day mark reads as its language writes it, and a country mark names its country by one rule
The day word of every language now says where the number goes ("DAY {day}",
"{day}日目", "第{day}天", "{day}. GÜN"), and one helper builds the mark for the
engine, the auto layout, a template and the Travel panel, so Japanese,
Korean and Chinese no longer read "日目 3". A word stored without the
placeholder is followed by the number as before. The panel's own day word is
gone with its only reader.
A country mark carries the name as its words beside the outline and a flag
mark sets it small beside the flag, the same for the engine's value, the
panel's tile, the assistant's add and a template's country mark; a flag in a
template keeps the place its name was drawn in. A flag or country mark asked
for by its own code is named after that country without the journey having
to name one.
This commit is contained in:
@@ -4,8 +4,8 @@ import type {
|
||||
BookBadgeVariant, BookElement, BookMapScope, BookMetric, BookPageSetup, BookTravelContext, JourneyStats,
|
||||
} from '@trek/shared'
|
||||
import {
|
||||
BOOK_METRICS, bookBadgeValue, bookCountryName, bookElementId as uid, bookTravelBadge, bookTravelCountries,
|
||||
bookTravelMap, bookTravelSize, bookTravelStats,
|
||||
BOOK_METRICS, bookBadgeValue, bookCountryMark, bookCountryName, bookElementId as uid, bookTravelBadge,
|
||||
bookTravelCountries, bookTravelMap, bookTravelSize, bookTravelStats,
|
||||
} from '@trek/shared'
|
||||
import { useStudioStore } from '../../store/studioStore'
|
||||
import { PanelHead } from './StudioPanelHead'
|
||||
@@ -170,16 +170,14 @@ export function StudioTravelPanel({
|
||||
* What the book engine's factories read: the journey, its recorded way and
|
||||
* the words in the reader's language. Every tile below is built by the
|
||||
* factory the engine's `add` calls. Where it lands is the panel's own:
|
||||
* centred across the spread, where `add` takes the right page. Two words are
|
||||
* still the panel's too, so a mark placed here and one the assistant adds
|
||||
* can read differently: the country mark carries the name in `text`, where
|
||||
* the engine's value has it in `sub`, and the day mark says `dayWord`, where
|
||||
* the engine says `day` (the two differ in ja, ko, zh and zh-TW).
|
||||
* centred across the spread, where `add` takes the right page. The day word
|
||||
* is the engine's too, handed over as its template: `t` leaves the `{day}`
|
||||
* in it untouched, and `bookDayText` puts the number there.
|
||||
*/
|
||||
const travel: BookTravelContext = {
|
||||
locale, stats, path, entries: [],
|
||||
labels: {
|
||||
day: t('journey.studio.dayWord'), stations: t('journey.studio.stations'), summary: t('journey.studio.summary'),
|
||||
day: t('journey.studio.day'), stations: t('journey.studio.stations'), summary: t('journey.studio.summary'),
|
||||
countries: t('journey.studio.countries'), distance: t('journey.studio.metric.distance'),
|
||||
pros: t('journey.editor.pros'), cons: t('journey.editor.cons'),
|
||||
},
|
||||
@@ -564,7 +562,7 @@ export function StudioTravelPanel({
|
||||
*/}
|
||||
<div className="st-travel-grid" style={{ marginTop: 6 }}>
|
||||
{stats.countries.slice(0, 12).map(c => {
|
||||
const el = badgeEl('country', { text: countryName(c.code), sub: '', code: c.code })
|
||||
const el = badgeEl('country', bookCountryMark('country', c.code, countryName(c.code)))
|
||||
return (
|
||||
<Card key={`mark-${c.code}`} label={countryName(c.code)} onClick={() => place(el)}>
|
||||
<TravelPreview el={el} minHeight={30} maxHeight={44} />
|
||||
|
||||
@@ -296,6 +296,8 @@ export function useJourneyStudio() {
|
||||
// line over a route somebody had actually walked.
|
||||
path,
|
||||
stationsLabel: t('journey.studio.stations'),
|
||||
// The template as it stands ("DAY {day}", "{day}日目"): without params `t`
|
||||
// leaves the `{day}` alone, and the layout puts each chip's number there.
|
||||
dayLabel: t('journey.studio.day'),
|
||||
summaryLabel: t('journey.studio.summary'),
|
||||
countriesLabel: t('journey.studio.countries'),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// STTRV-001 to STTRV-006: the Travel panel places what the book engine's factories build, so a figure, a map, a
|
||||
// country or a mark added by hand is the element the assistant's `add` adds. Only the frame is the panel's own:
|
||||
// centred across the spread rather than on the right-hand page.
|
||||
// STTRV-001 to STTRV-006 and STTRV-009: the Travel panel places what the book engine's factories build, so a figure,
|
||||
// a map, a country or a mark added by hand is the element the assistant's `add` adds. Only the frame is the panel's
|
||||
// own: centred across the spread rather than on the right-hand page.
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import type { BookDocument, BookElement, BookFrame, BookTravelContext, JourneyStats } from '@trek/shared';
|
||||
@@ -94,7 +94,7 @@ const travel: BookTravelContext = {
|
||||
path: PATH,
|
||||
entries: [],
|
||||
labels: {
|
||||
day: 'journey.studio.dayWord',
|
||||
day: 'journey.studio.day',
|
||||
stations: 'journey.studio.stations',
|
||||
summary: 'journey.studio.summary',
|
||||
countries: 'journey.studio.countries',
|
||||
@@ -117,13 +117,14 @@ const ANY_FRAME: BookFrame = { x: 0, y: 0, w: 1, h: 1 };
|
||||
/** An element apart from what the panel decides itself: the id it mints and where the frame goes. */
|
||||
const content = (el: BookElement) => ({ ...el, id: '', frame: ANY_FRAME });
|
||||
|
||||
function open(journey: JourneyStats = stats) {
|
||||
/** The panel on a journey, its words answered by `t`: the key itself unless a case says otherwise. */
|
||||
function open(journey: JourneyStats = stats, t: (k: string) => string = (k) => k) {
|
||||
return render(
|
||||
<StudioTravelPanel
|
||||
page={page}
|
||||
stats={journey}
|
||||
path={PATH}
|
||||
t={(k) => k}
|
||||
t={t}
|
||||
locale="en"
|
||||
canEdit={false}
|
||||
onToggleStop={async () => true}
|
||||
@@ -225,7 +226,7 @@ describe('the Travel panel builds through the book engine', () => {
|
||||
|
||||
expect(screen.queryByRole('button', { name: 'journey.studio.dateMark' })).toBeNull();
|
||||
fireEvent.click(card('journey.studio.dayMark'));
|
||||
expect(placed()).toMatchObject({ variant: 'day', text: 'journey.studio.dayWord 1', style: 'chip' });
|
||||
expect(placed()).toMatchObject({ variant: 'day', text: 'journey.studio.day 1', style: 'chip' });
|
||||
|
||||
const [outline, mark] = screen.getAllByRole('button', { name: 'Iceland' });
|
||||
fireEvent.click(outline);
|
||||
@@ -237,4 +238,20 @@ describe('the Travel panel builds through the book engine', () => {
|
||||
fireEvent.click(mark);
|
||||
expect(placed()).toMatchObject({ kind: 'badge', variant: 'country', text: 'Iceland', sub: '', code: 'IS' });
|
||||
});
|
||||
|
||||
it('STTRV-009: places a country mark as the engine makes one, and the day where its word puts it', () => {
|
||||
open(stats, (k) => (k === 'journey.studio.day' ? '{day}日目' : k));
|
||||
|
||||
const [, mark] = screen.getAllByRole('button', { name: 'Iceland' });
|
||||
fireEvent.click(mark);
|
||||
const value = bookBadgeValue(travel, 'country', null);
|
||||
expect(value).toEqual({ text: 'Iceland', sub: '', code: 'IS' });
|
||||
if (!value) throw new Error('the engine has no country mark for this journey');
|
||||
const engine = bookTravelBadge({ id: 'bd', frame: ANY_FRAME, variant: 'country', value });
|
||||
expect(content(placed())).toEqual(content(engine));
|
||||
expect(placed().frame).toEqual(spreadCentre(bookTravelSize('badge', page, { variant: 'country' })));
|
||||
|
||||
fireEvent.click(card('journey.studio.dayMark'));
|
||||
expect(placed()).toMatchObject({ variant: 'day', text: '1日目' });
|
||||
});
|
||||
});
|
||||
|
||||
@@ -214,7 +214,7 @@ describe('what the engine reads', () => {
|
||||
|
||||
expect(travel.entries.map((e) => [e.id, e.title, e.mood])).toEqual([[entry.id, 'Alfama', 'amazing']]);
|
||||
expect(travel.locale).toBe('de-DE');
|
||||
expect(travel.labels).toMatchObject({ day: 'TAG', stations: 'Stationen', pros: 'Pro', cons: 'Contra' });
|
||||
expect(travel.labels).toMatchObject({ day: 'TAG {day}', stations: 'Stationen', pros: 'Pro', cons: 'Contra' });
|
||||
expect(travel.path).toEqual([]);
|
||||
expect((await edit.wordsFor(owner.id)).locale).toBe('de-DE');
|
||||
});
|
||||
|
||||
@@ -19,12 +19,17 @@ describe('the book words', () => {
|
||||
it('JBLBL-002: the words come from the locale table, in the locale the book formats in', async () => {
|
||||
const french = await loadBookWords('fr');
|
||||
expect(french.locale).toBe('fr-FR');
|
||||
expect(french.labels).toMatchObject({ day: 'JOUR', stations: 'Étapes', summary: 'Résumé', countries: 'Pays' });
|
||||
expect(french.labels).toMatchObject({
|
||||
day: 'JOUR {day}',
|
||||
stations: 'Étapes',
|
||||
summary: 'Résumé',
|
||||
countries: 'Pays',
|
||||
});
|
||||
const english = await loadBookWords('xx');
|
||||
expect(english).toEqual({
|
||||
locale: 'en-US',
|
||||
labels: {
|
||||
day: 'DAY',
|
||||
day: 'DAY {day}',
|
||||
stations: 'Stations',
|
||||
summary: 'Summary',
|
||||
countries: 'Countries',
|
||||
|
||||
@@ -256,10 +256,12 @@ export function coordsMark(
|
||||
return badgeEl(newId, frame, 'coords', { text: formatBookCoords(lat, lng) }, { style: 'plain', textScale: 0.7 });
|
||||
}
|
||||
|
||||
/** The "DAY 5" chip. Small, solid, and the only filled shape on most pages. */
|
||||
export function dayChip(newId: NewId, frame: BookFrame, day: number | null | undefined, label: string) {
|
||||
if (!day) return null;
|
||||
return badgeEl(newId, frame, 'day', { text: `${label} ${day}` }, { style: 'chip', textScale: 0.75 });
|
||||
/**
|
||||
* The "DAY 5" chip, its words made by `bookDayText`. Small, solid, and the
|
||||
* only filled shape on most pages.
|
||||
*/
|
||||
export function dayChip(newId: NewId, frame: BookFrame, text: string) {
|
||||
return badgeEl(newId, frame, 'day', { text }, { style: 'chip', textScale: 0.75 });
|
||||
}
|
||||
|
||||
/** A rule along the foot with a dot showing how far into the journey this is. */
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { formatBookDate } from '../book-text';
|
||||
import { bookDayText } from '../book-travel';
|
||||
import type { BookElement, BookSpread } from '../book.schema';
|
||||
import {
|
||||
ACCENT,
|
||||
@@ -138,8 +139,7 @@ function footMarks(ctx: EntryContext, els: BookElement[], at: { x: number; y: nu
|
||||
const t = total && total > 1 ? Math.min(1, Math.max(0, (day - 1) / (total - 1))) : 0;
|
||||
const cw = 24;
|
||||
const cx = Math.min(x + w - cw, Math.max(x, x + w * t - cw / 2));
|
||||
const chip = dayChip(newId, { x: cx, y: y - 11, w: cw, h: 7 }, day, input.dayLabel);
|
||||
if (chip) els.push(chip);
|
||||
els.push(dayChip(newId, { x: cx, y: y - 11, w: cw, h: 7 }, bookDayText(input.dayLabel, day)));
|
||||
}
|
||||
|
||||
/** The story, bound to the entry, set in a column. */
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { bookCoordValue, formatBookCoords, formatBookDate } from '../book-text';
|
||||
import { bookCountryMark, bookCountryName, bookDayText } from '../book-travel';
|
||||
import {
|
||||
MAX_TEXT_LENGTH,
|
||||
type BookBadgeElement,
|
||||
@@ -32,7 +33,7 @@ export interface AutoTemplateContext {
|
||||
page: BookPageSetup;
|
||||
locale: string;
|
||||
stats: JourneyStats | null;
|
||||
/** Already translated, because this module has no translation context. */
|
||||
/** The day mark's label ("DAY {day}"), already translated, because this module has no translation context. */
|
||||
dayLabel: string;
|
||||
newId: NewId;
|
||||
}
|
||||
@@ -143,14 +144,11 @@ function fillText(
|
||||
* answer keeps the one it was drawn with.
|
||||
*/
|
||||
function fillBadge(el: BookBadgeElement, entry: AutoEntry, ctx: AutoTemplateContext): void {
|
||||
if (el.variant === 'day' && entry.dayNumber) el.text = `${ctx.dayLabel} ${entry.dayNumber}`;
|
||||
if (el.variant === 'day' && entry.dayNumber) el.text = bookDayText(ctx.dayLabel, entry.dayNumber);
|
||||
if (el.variant === 'coords' && entry.lat != null && entry.lng != null) {
|
||||
el.text = formatBookCoords(entry.lat, entry.lng);
|
||||
}
|
||||
if ((el.variant === 'flag' || el.variant === 'country') && entry.country) {
|
||||
el.code = entry.country;
|
||||
el.text = countryName(entry.country, ctx).toUpperCase();
|
||||
}
|
||||
if ((el.variant === 'flag' || el.variant === 'country') && entry.country) fillCountry(el, entry.country, ctx);
|
||||
if (el.variant === 'date' && entry.date) {
|
||||
const d = new Date(`${entry.date}T00:00:00`);
|
||||
if (!Number.isNaN(d.getTime())) {
|
||||
@@ -163,11 +161,20 @@ function fillBadge(el: BookBadgeElement, entry: AutoEntry, ctx: AutoTemplateCont
|
||||
}
|
||||
}
|
||||
|
||||
function countryName(code: string, ctx: AutoTemplateContext): string {
|
||||
const known = ctx.stats?.countries.find((c) => c.code === code);
|
||||
try {
|
||||
return new Intl.DisplayNames([ctx.locale], { type: 'region' }).of(code) ?? known?.name ?? code;
|
||||
} catch {
|
||||
return known?.name ?? code;
|
||||
/**
|
||||
* A country mark takes the rule the engine and the Travel panel follow
|
||||
* (`bookCountryMark`): the name as its words, and the drawn words beside them
|
||||
* go. A flag keeps the place its template set the name in: in capitals as its
|
||||
* words, the way the auto layout sets a flag, or beside the flag (`sub`) where
|
||||
* it was placed from the panel, so no drawn name is left next to the new one.
|
||||
*/
|
||||
function fillCountry(el: BookBadgeElement, code: string, ctx: AutoTemplateContext): void {
|
||||
const name = bookCountryName(code, ctx.locale, ctx.stats);
|
||||
if (el.variant === 'country') {
|
||||
Object.assign(el, bookCountryMark('country', code, name));
|
||||
return;
|
||||
}
|
||||
el.code = code;
|
||||
if (el.text || !el.sub) el.text = name.toUpperCase();
|
||||
else el.sub = name;
|
||||
}
|
||||
|
||||
@@ -67,7 +67,11 @@ export interface AutoInput {
|
||||
stats: JourneyStats | null;
|
||||
/** The heading over a list of bare stops, already translated. */
|
||||
stationsLabel: string;
|
||||
/** The word before a day number on a chip ("DAY 5"). Already translated. */
|
||||
/**
|
||||
* The words of a day chip, already translated: `{day}` stands where the
|
||||
* number goes ("DAY {day}", "{day}日目"), and a word without it is followed
|
||||
* by the number ("DAY 5"). See `bookDayText`.
|
||||
*/
|
||||
dayLabel: string;
|
||||
/**
|
||||
* The real geometry of the route, when the journey has any (GPX and KML
|
||||
|
||||
@@ -183,11 +183,20 @@ describe('add', () => {
|
||||
});
|
||||
|
||||
it('BOOKEL-017: a flag or country mark asked for by its own code is labelled with that country', () => {
|
||||
expect(added({ kind: 'badge', variant: 'flag' })).toMatchObject({ code: 'IS', sub: 'Iceland' });
|
||||
expect(added({ kind: 'badge', variant: 'flag', code: 'PT' })).toMatchObject({ code: 'PT', sub: 'Portugal' });
|
||||
// A flag sets the name beside the flag (sub); a country mark has it as its words, the outline beside them.
|
||||
expect(added({ kind: 'badge', variant: 'flag' })).toMatchObject({ code: 'IS', text: '', sub: 'Iceland' });
|
||||
const portugal = added({ kind: 'badge', variant: 'flag', code: 'PT' });
|
||||
expect(portugal).toMatchObject({ code: 'PT', text: '', sub: 'Portugal' });
|
||||
expect(added({ kind: 'badge', variant: 'country' })).toMatchObject({ code: 'IS', text: 'Iceland', sub: '' });
|
||||
const norway = added({ kind: 'badge', variant: 'country', entryId: 7, code: 'NO' });
|
||||
expect(norway).toMatchObject({ code: 'NO', sub: 'Norway' });
|
||||
expect(norway).toMatchObject({ code: 'NO', text: 'Norway', sub: '' });
|
||||
expect(added({ kind: 'badge', variant: 'flag', code: 'PT', sub: 'Lisboa' })).toMatchObject({ sub: 'Lisboa' });
|
||||
const lisboa = added({ kind: 'badge', variant: 'country', code: 'PT', text: 'Lisboa' });
|
||||
expect(lisboa).toMatchObject({ code: 'PT', text: 'Lisboa', sub: '' });
|
||||
// Its own code names the country on a journey whose figures name none; without one there is nothing to show.
|
||||
const noCountries: BookOpsContext = { ...ctx, travel: { ...travel, stats: { ...stats, countries: [] } } };
|
||||
expect(added({ kind: 'badge', variant: 'flag', code: 'PT' }, noCountries)).toMatchObject({ sub: 'Portugal' });
|
||||
expect(addRefusal({ kind: 'badge', variant: 'flag' }, noCountries)).toBe('text_required');
|
||||
// Another mark's code is its own (a mood, the weather) and names no country.
|
||||
expect(added({ kind: 'badge', variant: 'mood', code: 'good', text: 'Good' })).toMatchObject({ sub: '' });
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { relayoutSpread } from './auto/auto-book';
|
||||
import type { AutoInput } from './auto/auto-types';
|
||||
import type { AutoEntry, AutoInput } from './auto/auto-types';
|
||||
import { bookElementPropsSchema, type BOOK_ELEMENT_OP_SCHEMAS, type BookNewElement } from './book-element-ops.schema';
|
||||
import { bookGridElements, defaultBookGridBox, findBookGrid } from './book-grids';
|
||||
import {
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
} from './book-ops-core';
|
||||
import {
|
||||
bookBadgeValue,
|
||||
bookCountryMark,
|
||||
bookCountryName,
|
||||
bookEntryListItems,
|
||||
bookTravelBadge,
|
||||
@@ -334,7 +335,7 @@ function newBadge(spec: Extract<TravelSpec, { kind: 'badge' }>, id: string, at:
|
||||
if (spec.entryId !== undefined && !entry) {
|
||||
throw failOp('entry_not_found', `entry ${spec.entryId} is not in this journey`, env.opIndex);
|
||||
}
|
||||
const resolved = travel ? bookBadgeValue(travel, spec.variant, entry) : null;
|
||||
const resolved = travel ? badgeValue(spec, travel, entry) : null;
|
||||
const ownCode = spec.variant === 'mood' ? entry?.mood : spec.variant === 'weather' ? entry?.weather : undefined;
|
||||
const text = spec.text ?? resolved?.text;
|
||||
if (text === undefined || (!text && !resolved)) {
|
||||
@@ -343,29 +344,25 @@ function newBadge(spec: Extract<TravelSpec, { kind: 'badge' }>, id: string, at:
|
||||
}
|
||||
const value = {
|
||||
text,
|
||||
sub: spec.sub ?? badgeSub(spec, resolved?.sub, resolved?.code, travel) ?? '',
|
||||
sub: spec.sub ?? resolved?.sub ?? '',
|
||||
code: spec.code ?? ownCode ?? resolved?.code ?? null,
|
||||
};
|
||||
const frame = at(bookTravelSize('badge', env.page, { variant: spec.variant }));
|
||||
return bookTravelBadge({ id, frame, variant: spec.variant, value });
|
||||
}
|
||||
|
||||
/** The marks whose code names a country. */
|
||||
const COUNTRY_MARKS: ReadonlySet<string> = new Set(['flag', 'country']);
|
||||
|
||||
/**
|
||||
* A flag or country mark asked for by its own code is labelled with that
|
||||
* country; the journey's value names its first country, the one a mark
|
||||
* without a code shows.
|
||||
* The words the journey gives a mark. A flag or country mark asked for by its
|
||||
* own code is labelled with that country, its name where the mark's rule puts
|
||||
* it (`bookCountryMark`); without a code it shows the entry's country or the
|
||||
* journey's first.
|
||||
*/
|
||||
function badgeSub(
|
||||
spec: Extract<TravelSpec, { kind: 'badge' }>,
|
||||
sub: string | undefined,
|
||||
code: string | null | undefined,
|
||||
travel: BookTravelContext | undefined,
|
||||
): string | undefined {
|
||||
if (!travel || !spec.code || !COUNTRY_MARKS.has(spec.variant)) return sub;
|
||||
return spec.code === code ? sub : bookCountryName(spec.code, travel.locale, travel.stats);
|
||||
function badgeValue(spec: Extract<TravelSpec, { kind: 'badge' }>, travel: BookTravelContext, entry: AutoEntry | null) {
|
||||
const { variant, code } = spec;
|
||||
if (code && (variant === 'flag' || variant === 'country')) {
|
||||
return bookCountryMark(variant, code, bookCountryName(code, travel.locale, travel.stats));
|
||||
}
|
||||
return bookBadgeValue(travel, variant, entry);
|
||||
}
|
||||
|
||||
function newList(spec: Extract<TravelSpec, { kind: 'list' }>, id: string, at: At, env: ElementOpEnv): BookElement {
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
import { buildBook } from './auto/auto-book';
|
||||
import { applyAutoTemplate } from './auto/auto-template-apply';
|
||||
import type { AutoEntry } from './auto/auto-types';
|
||||
import {
|
||||
bookBadgeValue,
|
||||
bookCountryMark,
|
||||
bookCountryName,
|
||||
bookDayText,
|
||||
bookEntryListItems,
|
||||
bookTravelCountries,
|
||||
bookTravelMap,
|
||||
@@ -13,7 +17,7 @@ import {
|
||||
routeFor,
|
||||
type BookTravelContext,
|
||||
} from './book-travel';
|
||||
import { bookElementSchema, bookPageSetupSchema, type BookElement } from './book.schema';
|
||||
import { bookBadgeElementSchema, bookElementSchema, bookPageSetupSchema, type BookElement } from './book.schema';
|
||||
import type { JourneyStats } from './journey-stats.schema';
|
||||
|
||||
import { describe, expect, it } from 'vitest';
|
||||
@@ -173,4 +177,73 @@ describe('book travel', () => {
|
||||
expect(refreshPatch(map, moved)).toMatchObject({ countries: ['IS'] });
|
||||
expect(isStale(figures, null)).toBe(false);
|
||||
});
|
||||
|
||||
it('BOOKTRV-008: puts the day number where the label says, and after a label that does not say', () => {
|
||||
expect(bookDayText('DAY {day}', 5)).toBe('DAY 5');
|
||||
expect(bookDayText('{day}日目', 3)).toBe('3日目');
|
||||
expect(bookDayText('第{day}天', 12)).toBe('第12天');
|
||||
expect(bookDayText('DAY', 5)).toBe('DAY 5');
|
||||
const japanese: BookTravelContext = { ...ctx, labels: { ...ctx.labels, day: '{day}日目' } };
|
||||
expect(bookBadgeValue(japanese, 'day', entry)).toEqual({ text: '5日目', sub: '', code: null });
|
||||
expect(bookBadgeValue(japanese, 'day', null)?.text).toBe('1日目');
|
||||
// The auto layout's chip at the foot of an entry says it the same way.
|
||||
const doc = buildBook({
|
||||
locale: 'ja',
|
||||
title: 'North',
|
||||
subtitle: null,
|
||||
coverPhotoId: null,
|
||||
entries: [{ ...entry, story: 'Whales off the harbour.' }],
|
||||
page: bookPageSetupSchema.parse({}),
|
||||
stats,
|
||||
stationsLabel: 'Stations',
|
||||
dayLabel: '{day}日目',
|
||||
summaryLabel: 'Summary',
|
||||
countriesLabel: 'Countries',
|
||||
templates: [],
|
||||
});
|
||||
const elements = doc.spreads.flatMap((s) => s.elements);
|
||||
const days = elements.flatMap((e) => (e.kind === 'badge' && e.variant === 'day' ? [e.text] : []));
|
||||
expect(days).toEqual(['5日目']);
|
||||
});
|
||||
|
||||
it('BOOKTRV-009: names the country as the words of a country mark and beside the flag of a flag mark', () => {
|
||||
expect(bookBadgeValue(ctx, 'country', entry)).toEqual({ text: 'Iceland', sub: '', code: 'IS' });
|
||||
expect(bookBadgeValue({ ...ctx, locale: 'de' }, 'country', null)).toEqual({ text: 'Island', sub: '', code: 'IS' });
|
||||
expect(bookBadgeValue(ctx, 'flag', null)).toEqual({ text: '', sub: 'Iceland', code: 'IS' });
|
||||
expect(bookBadgeValue({ ...ctx, stats: null }, 'country', null)).toBeNull();
|
||||
expect(bookCountryMark('country', 'PT', 'Portugal')).toEqual({ text: 'Portugal', sub: '', code: 'PT' });
|
||||
expect(bookCountryMark('flag', 'PT', 'Portugal')).toEqual({ text: '', sub: 'Portugal', code: 'PT' });
|
||||
});
|
||||
|
||||
it('BOOKTRV-010: fills the day and country marks of a template by the same rules, a flag where it was drawn', () => {
|
||||
const frame = { x: 0.1, y: 0.1, w: 0.2, h: 0.05 };
|
||||
const mark = (variant: 'day' | 'country' | 'flag', text: string, sub: string) =>
|
||||
bookBadgeElementSchema.parse({ id: variant, kind: 'badge', variant, text, sub, frame });
|
||||
// Flags set the auto layout's way (the name as its words, or no words yet) and one placed from the panel.
|
||||
const template = {
|
||||
id: 'marks',
|
||||
background: null,
|
||||
elements: [
|
||||
mark('day', 'DAY 1', ''),
|
||||
mark('country', 'FRANCE', 'Paris'),
|
||||
mark('flag', 'FRANCE', ''),
|
||||
mark('flag', '', ''),
|
||||
mark('flag', '', 'France'),
|
||||
],
|
||||
};
|
||||
const fill = {
|
||||
page: bookPageSetupSchema.parse({}),
|
||||
locale: 'en',
|
||||
stats,
|
||||
dayLabel: '{day}日目',
|
||||
newId: (p: string) => p,
|
||||
};
|
||||
expect(applyAutoTemplate(template, entry, fill).elements).toMatchObject([
|
||||
{ variant: 'day', text: '5日目' },
|
||||
{ variant: 'country', text: 'Iceland', sub: '', code: 'IS' },
|
||||
{ variant: 'flag', text: 'ICELAND', sub: '', code: 'IS' },
|
||||
{ variant: 'flag', text: 'ICELAND', sub: '', code: 'IS' },
|
||||
{ variant: 'flag', text: '', sub: 'Iceland', code: 'IS' },
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -121,6 +121,7 @@ export function refreshPatch(el: BookElement, stats: JourneyStats): Partial<Book
|
||||
|
||||
/** What the factories know about the journey, the words already in the book's language. */
|
||||
export interface BookTravelLabels {
|
||||
/** The day mark's words, `{day}` standing where the number goes (`bookDayText`). */
|
||||
day: string;
|
||||
stations: string;
|
||||
summary: string;
|
||||
@@ -283,6 +284,34 @@ export function bookTravelCountries(
|
||||
};
|
||||
}
|
||||
|
||||
/** Where the number goes in a day mark's label. */
|
||||
const DAY_SLOT = '{day}';
|
||||
|
||||
/**
|
||||
* A day mark's words. The label says where the number goes with `{day}`, so a
|
||||
* language that puts it first or inside the word reads as it should ("3日目",
|
||||
* "第3天"); a label without one (a word stored before the placeholder, or a
|
||||
* caller's own) is followed by the number, the way it always was ("DAY 3").
|
||||
*/
|
||||
export function bookDayText(label: string, day: number): string {
|
||||
// `replace`, not `replaceAll`: the client compiles this file against an ES2020 lib. A label holds the slot once.
|
||||
return label.includes(DAY_SLOT) ? label.replace(DAY_SLOT, String(day)) : `${label} ${day}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* A flag or a country mark's words for one country, the one rule for the
|
||||
* engine's value, the Travel panel's mark and a template's country mark. A
|
||||
* country mark draws the outline beside the name, so the name is its words
|
||||
* (`text`); a flag mark sets the name in small capitals beside the flag (`sub`).
|
||||
*/
|
||||
export function bookCountryMark(
|
||||
variant: 'flag' | 'country',
|
||||
code: string,
|
||||
name: string,
|
||||
): { text: string; sub: string; code: string } {
|
||||
return variant === 'country' ? { text: name, sub: '', code } : { text: '', sub: name, code };
|
||||
}
|
||||
|
||||
/** The words a mark carries, resolved from an entry or the journey; null when nothing says what it would show. */
|
||||
export function bookBadgeValue(
|
||||
ctx: BookTravelContext,
|
||||
@@ -298,7 +327,7 @@ export function bookBadgeValue(
|
||||
switch (variant) {
|
||||
case 'day': {
|
||||
const day = entry ? entry.dayNumber : 1;
|
||||
return day ? { text: `${ctx.labels.day} ${day}`, sub: '', code: null } : null;
|
||||
return day ? { text: bookDayText(ctx.labels.day, day), sub: '', code: null } : null;
|
||||
}
|
||||
case 'date': {
|
||||
const d = date ? new Date(`${date}T00:00:00`) : null;
|
||||
@@ -313,7 +342,7 @@ export function bookBadgeValue(
|
||||
}
|
||||
case 'flag':
|
||||
case 'country':
|
||||
return country ? { text: '', sub: bookCountryName(country, ctx.locale, stats), code: country } : null;
|
||||
return country ? bookCountryMark(variant, country, bookCountryName(country, ctx.locale, stats)) : null;
|
||||
case 'distance':
|
||||
if (!stats) return null;
|
||||
return { text: formatDistance(stats.distance, ctx.locale), sub: ctx.labels.distance, code: null };
|
||||
|
||||
@@ -320,7 +320,7 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.emptySpread': 'This spread is still empty', // en-fallback
|
||||
'journey.studio.autoLayout': 'Auto layout', // en-fallback
|
||||
'journey.studio.export': 'Export', // en-fallback
|
||||
'journey.studio.day': 'اليوم',
|
||||
'journey.studio.day': 'اليوم {day}',
|
||||
'journey.studio.stations': 'المحطات',
|
||||
'journey.studio.peersHere': 'هنا',
|
||||
'journey.studio.folioAuto': 'تلقائي',
|
||||
@@ -481,7 +481,6 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.marks': 'العلامات',
|
||||
'journey.studio.dateMark': 'التاريخ',
|
||||
'journey.studio.dayMark': 'عدّاد الأيام',
|
||||
'journey.studio.dayWord': 'اليوم',
|
||||
'journey.studio.coordsMark': 'الإحداثيات',
|
||||
'journey.studio.coordsDms': 'درجات',
|
||||
'journey.studio.coordsDecimal': 'عشرية',
|
||||
|
||||
@@ -322,7 +322,7 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.emptySpread': 'Bu açılım hələ boşdur',
|
||||
'journey.studio.autoLayout': 'Avtomatik tərtibat',
|
||||
'journey.studio.export': 'İxrac et',
|
||||
'journey.studio.day': 'GÜN',
|
||||
'journey.studio.day': 'GÜN {day}',
|
||||
'journey.studio.stations': 'Dayanacaqlar',
|
||||
'journey.studio.peersHere': 'burada',
|
||||
'journey.studio.folioAuto': 'Avtomatik',
|
||||
@@ -495,7 +495,6 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.marks': 'Nişanlar',
|
||||
'journey.studio.dateMark': 'Tarix',
|
||||
'journey.studio.dayMark': 'Gün sayğacı',
|
||||
'journey.studio.dayWord': 'GÜN',
|
||||
'journey.studio.coordsMark': 'Koordinatlar',
|
||||
'journey.studio.coordsDms': 'Dərəcə',
|
||||
'journey.studio.coordsDecimal': 'Onluq',
|
||||
|
||||
@@ -298,7 +298,7 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.emptySpread': 'This spread is still empty', // en-fallback
|
||||
'journey.studio.autoLayout': 'Auto layout', // en-fallback
|
||||
'journey.studio.export': 'Export', // en-fallback
|
||||
'journey.studio.day': 'DIA',
|
||||
'journey.studio.day': 'DIA {day}',
|
||||
'journey.studio.stations': 'Etapas',
|
||||
'journey.studio.peersHere': 'aqui',
|
||||
'journey.studio.folioAuto': 'Automático',
|
||||
@@ -454,7 +454,6 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.marks': 'Marcas',
|
||||
'journey.studio.dateMark': 'Data',
|
||||
'journey.studio.dayMark': 'Contador de dias',
|
||||
'journey.studio.dayWord': 'DIA',
|
||||
'journey.studio.coordsMark': 'Coordenadas',
|
||||
'journey.studio.coordsDms': 'Graus',
|
||||
'journey.studio.coordsDecimal': 'Decimal',
|
||||
|
||||
@@ -297,7 +297,7 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.emptySpread': 'This spread is still empty', // en-fallback
|
||||
'journey.studio.autoLayout': 'Auto layout', // en-fallback
|
||||
'journey.studio.export': 'Export', // en-fallback
|
||||
'journey.studio.day': 'DIA',
|
||||
'journey.studio.day': 'DIA {day}',
|
||||
'journey.studio.stations': 'Etapes',
|
||||
'journey.studio.peersHere': 'aquí',
|
||||
'journey.studio.folioAuto': 'Automàtic',
|
||||
@@ -453,7 +453,6 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.marks': 'Marques',
|
||||
'journey.studio.dateMark': 'Data',
|
||||
'journey.studio.dayMark': 'Comptador de dies',
|
||||
'journey.studio.dayWord': 'DIA',
|
||||
'journey.studio.coordsMark': 'Coordenades',
|
||||
'journey.studio.coordsDms': 'Graus',
|
||||
'journey.studio.coordsDecimal': 'Decimal',
|
||||
|
||||
@@ -302,7 +302,7 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.emptySpread': 'This spread is still empty', // en-fallback
|
||||
'journey.studio.autoLayout': 'Auto layout', // en-fallback
|
||||
'journey.studio.export': 'Export', // en-fallback
|
||||
'journey.studio.day': 'DEN',
|
||||
'journey.studio.day': 'DEN {day}',
|
||||
'journey.studio.stations': 'Zastávky',
|
||||
'journey.studio.peersHere': 'zde',
|
||||
'journey.studio.folioAuto': 'Automaticky',
|
||||
@@ -458,7 +458,6 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.marks': 'Značky',
|
||||
'journey.studio.dateMark': 'Datum',
|
||||
'journey.studio.dayMark': 'Počítadlo dní',
|
||||
'journey.studio.dayWord': 'DEN',
|
||||
'journey.studio.coordsMark': 'Souřadnice',
|
||||
'journey.studio.coordsDms': 'Stupně',
|
||||
'journey.studio.coordsDecimal': 'Desetinné',
|
||||
|
||||
@@ -298,7 +298,7 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.emptySpread': 'Diese Doppelseite ist noch leer',
|
||||
'journey.studio.autoLayout': 'Automatisch anordnen',
|
||||
'journey.studio.export': 'Exportieren',
|
||||
'journey.studio.day': 'TAG',
|
||||
'journey.studio.day': 'TAG {day}',
|
||||
'journey.studio.stations': 'Stationen',
|
||||
'journey.studio.peersHere': 'hier',
|
||||
'journey.studio.folioAuto': 'Automatisch',
|
||||
@@ -454,7 +454,6 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.marks': 'Marken',
|
||||
'journey.studio.dateMark': 'Datum',
|
||||
'journey.studio.dayMark': 'Tageszähler',
|
||||
'journey.studio.dayWord': 'TAG',
|
||||
'journey.studio.coordsMark': 'Koordinaten',
|
||||
'journey.studio.coordsDms': 'Grad',
|
||||
'journey.studio.coordsDecimal': 'Dezimal',
|
||||
|
||||
@@ -296,7 +296,7 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.emptySpread': 'This spread is still empty',
|
||||
'journey.studio.autoLayout': 'Auto layout',
|
||||
'journey.studio.export': 'Export',
|
||||
'journey.studio.day': 'DAY',
|
||||
'journey.studio.day': 'DAY {day}',
|
||||
'journey.studio.stations': 'Stations',
|
||||
'journey.studio.peersHere': 'here',
|
||||
'journey.studio.folioAuto': 'Automatic',
|
||||
@@ -451,7 +451,6 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.marks': 'Marks',
|
||||
'journey.studio.dateMark': 'Date',
|
||||
'journey.studio.dayMark': 'Day counter',
|
||||
'journey.studio.dayWord': 'DAY',
|
||||
'journey.studio.coordsMark': 'Coordinates',
|
||||
'journey.studio.coordsDms': 'Degrees',
|
||||
'journey.studio.coordsDecimal': 'Decimal',
|
||||
|
||||
@@ -298,7 +298,7 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.emptySpread': 'This spread is still empty', // en-fallback
|
||||
'journey.studio.autoLayout': 'Auto layout', // en-fallback
|
||||
'journey.studio.export': 'Export', // en-fallback
|
||||
'journey.studio.day': 'DÍA',
|
||||
'journey.studio.day': 'DÍA {day}',
|
||||
'journey.studio.stations': 'Etapas',
|
||||
'journey.studio.peersHere': 'aquí',
|
||||
'journey.studio.folioAuto': 'Automático',
|
||||
@@ -454,7 +454,6 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.marks': 'Marcas',
|
||||
'journey.studio.dateMark': 'Fecha',
|
||||
'journey.studio.dayMark': 'Contador de días',
|
||||
'journey.studio.dayWord': 'DÍA',
|
||||
'journey.studio.coordsMark': 'Coordenadas',
|
||||
'journey.studio.coordsDms': 'Grados',
|
||||
'journey.studio.coordsDecimal': 'Decimal',
|
||||
|
||||
@@ -298,7 +298,7 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.emptySpread': 'See lehepaar on veel tühi',
|
||||
'journey.studio.autoLayout': 'Automaatne paigutus',
|
||||
'journey.studio.export': 'Eksport',
|
||||
'journey.studio.day': 'PÄEV',
|
||||
'journey.studio.day': '{day}. PÄEV',
|
||||
'journey.studio.stations': 'Peatused',
|
||||
'journey.studio.peersHere': 'siin',
|
||||
'journey.studio.folioAuto': 'Automaatne',
|
||||
@@ -452,7 +452,6 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.marks': 'Märgised',
|
||||
'journey.studio.dateMark': 'Kuupäev',
|
||||
'journey.studio.dayMark': 'Päevaloendur',
|
||||
'journey.studio.dayWord': 'PÄEV',
|
||||
'journey.studio.coordsMark': 'Koordinaadid',
|
||||
'journey.studio.coordsDms': 'Kraadid',
|
||||
'journey.studio.coordsDecimal': 'Kümnendkujul',
|
||||
|
||||
@@ -297,7 +297,7 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.emptySpread': 'This spread is still empty', // en-fallback
|
||||
'journey.studio.autoLayout': 'Auto layout', // en-fallback
|
||||
'journey.studio.export': 'Export', // en-fallback
|
||||
'journey.studio.day': 'JOUR',
|
||||
'journey.studio.day': 'JOUR {day}',
|
||||
'journey.studio.stations': 'Étapes',
|
||||
'journey.studio.peersHere': 'ici',
|
||||
'journey.studio.folioAuto': 'Automatique',
|
||||
@@ -452,7 +452,6 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.marks': 'Repères',
|
||||
'journey.studio.dateMark': 'Date',
|
||||
'journey.studio.dayMark': 'Compteur de jours',
|
||||
'journey.studio.dayWord': 'JOUR',
|
||||
'journey.studio.coordsMark': 'Coordonnées',
|
||||
'journey.studio.coordsDms': 'Degrés',
|
||||
'journey.studio.coordsDecimal': 'Décimal',
|
||||
|
||||
@@ -300,7 +300,7 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.emptySpread': 'This spread is still empty', // en-fallback
|
||||
'journey.studio.autoLayout': 'Auto layout', // en-fallback
|
||||
'journey.studio.export': 'Export', // en-fallback
|
||||
'journey.studio.day': 'ΗΜΕΡΑ',
|
||||
'journey.studio.day': 'ΗΜΕΡΑ {day}',
|
||||
'journey.studio.stations': 'Στάσεις',
|
||||
'journey.studio.peersHere': 'εδώ',
|
||||
'journey.studio.folioAuto': 'Αυτόματα',
|
||||
@@ -457,7 +457,6 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.marks': 'Σημάνσεις',
|
||||
'journey.studio.dateMark': 'Ημερομηνία',
|
||||
'journey.studio.dayMark': 'Μετρητής ημερών',
|
||||
'journey.studio.dayWord': 'ΗΜΕΡΑ',
|
||||
'journey.studio.coordsMark': 'Συντεταγμένες',
|
||||
'journey.studio.coordsDms': 'Μοίρες',
|
||||
'journey.studio.coordsDecimal': 'Δεκαδικές',
|
||||
|
||||
@@ -297,7 +297,7 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.emptySpread': 'This spread is still empty', // en-fallback
|
||||
'journey.studio.autoLayout': 'Auto layout', // en-fallback
|
||||
'journey.studio.export': 'Export', // en-fallback
|
||||
'journey.studio.day': 'NAP',
|
||||
'journey.studio.day': '{day}. NAP',
|
||||
'journey.studio.stations': 'Állomások',
|
||||
'journey.studio.peersHere': 'itt',
|
||||
'journey.studio.folioAuto': 'Automatikus',
|
||||
@@ -451,7 +451,6 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.marks': 'Jelek',
|
||||
'journey.studio.dateMark': 'Dátum',
|
||||
'journey.studio.dayMark': 'Napszámláló',
|
||||
'journey.studio.dayWord': 'NAP',
|
||||
'journey.studio.coordsMark': 'Koordináták',
|
||||
'journey.studio.coordsDms': 'Fok',
|
||||
'journey.studio.coordsDecimal': 'Tizedes',
|
||||
|
||||
@@ -290,7 +290,7 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.emptySpread': 'This spread is still empty', // en-fallback
|
||||
'journey.studio.autoLayout': 'Auto layout', // en-fallback
|
||||
'journey.studio.export': 'Export', // en-fallback
|
||||
'journey.studio.day': 'HARI',
|
||||
'journey.studio.day': 'HARI {day}',
|
||||
'journey.studio.stations': 'Persinggahan',
|
||||
'journey.studio.peersHere': 'di sini',
|
||||
'journey.studio.folioAuto': 'Otomatis',
|
||||
@@ -443,7 +443,6 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.marks': 'Tanda',
|
||||
'journey.studio.dateMark': 'Tanggal',
|
||||
'journey.studio.dayMark': 'Penghitung hari',
|
||||
'journey.studio.dayWord': 'HARI',
|
||||
'journey.studio.coordsMark': 'Koordinat',
|
||||
'journey.studio.coordsDms': 'Derajat',
|
||||
'journey.studio.coordsDecimal': 'Desimal',
|
||||
|
||||
@@ -297,7 +297,7 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.emptySpread': 'This spread is still empty', // en-fallback
|
||||
'journey.studio.autoLayout': 'Auto layout', // en-fallback
|
||||
'journey.studio.export': 'Export', // en-fallback
|
||||
'journey.studio.day': 'GIORNO',
|
||||
'journey.studio.day': 'GIORNO {day}',
|
||||
'journey.studio.stations': 'Tappe',
|
||||
'journey.studio.peersHere': 'qui',
|
||||
'journey.studio.folioAuto': 'Automatico',
|
||||
@@ -453,7 +453,6 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.marks': 'Segni',
|
||||
'journey.studio.dateMark': 'Data',
|
||||
'journey.studio.dayMark': 'Contagiorni',
|
||||
'journey.studio.dayWord': 'GIORNO',
|
||||
'journey.studio.coordsMark': 'Coordinate',
|
||||
'journey.studio.coordsDms': 'Gradi',
|
||||
'journey.studio.coordsDecimal': 'Decimale',
|
||||
|
||||
@@ -288,7 +288,7 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.emptySpread': 'This spread is still empty', // en-fallback
|
||||
'journey.studio.autoLayout': 'Auto layout', // en-fallback
|
||||
'journey.studio.export': 'Export', // en-fallback
|
||||
'journey.studio.day': '日目',
|
||||
'journey.studio.day': '{day}日目',
|
||||
'journey.studio.stations': '立ち寄り先',
|
||||
'journey.studio.peersHere': '閲覧中',
|
||||
'journey.studio.folioAuto': '自動',
|
||||
@@ -441,7 +441,6 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.marks': 'マーク',
|
||||
'journey.studio.dateMark': '日付',
|
||||
'journey.studio.dayMark': '日数カウンター',
|
||||
'journey.studio.dayWord': 'DAY',
|
||||
'journey.studio.coordsMark': '座標',
|
||||
'journey.studio.coordsDms': '度分秒',
|
||||
'journey.studio.coordsDecimal': '十進度',
|
||||
|
||||
@@ -286,7 +286,7 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.emptySpread': 'This spread is still empty', // en-fallback
|
||||
'journey.studio.autoLayout': 'Auto layout', // en-fallback
|
||||
'journey.studio.export': 'Export', // en-fallback
|
||||
'journey.studio.day': '일차',
|
||||
'journey.studio.day': '{day}일차',
|
||||
'journey.studio.stations': '경유지',
|
||||
'journey.studio.peersHere': '접속 중',
|
||||
'journey.studio.folioAuto': '자동',
|
||||
@@ -438,7 +438,6 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.marks': '표시',
|
||||
'journey.studio.dateMark': '날짜',
|
||||
'journey.studio.dayMark': '일수 카운터',
|
||||
'journey.studio.dayWord': 'DAY',
|
||||
'journey.studio.coordsMark': '좌표',
|
||||
'journey.studio.coordsDms': '도분초',
|
||||
'journey.studio.coordsDecimal': '십진도',
|
||||
|
||||
@@ -298,7 +298,7 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.emptySpread': 'This spread is still empty', // en-fallback
|
||||
'journey.studio.autoLayout': 'Auto layout', // en-fallback
|
||||
'journey.studio.export': 'Export', // en-fallback
|
||||
'journey.studio.day': 'DAG',
|
||||
'journey.studio.day': 'DAG {day}',
|
||||
'journey.studio.stations': 'Etappes',
|
||||
'journey.studio.peersHere': 'hier',
|
||||
'journey.studio.folioAuto': 'Automatisch',
|
||||
@@ -454,7 +454,6 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.marks': 'Markeringen',
|
||||
'journey.studio.dateMark': 'Datum',
|
||||
'journey.studio.dayMark': 'Dagteller',
|
||||
'journey.studio.dayWord': 'DAG',
|
||||
'journey.studio.coordsMark': 'Coördinaten',
|
||||
'journey.studio.coordsDms': 'Graden',
|
||||
'journey.studio.coordsDecimal': 'Decimaal',
|
||||
|
||||
@@ -310,7 +310,7 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.emptySpread': 'This spread is still empty', // en-fallback
|
||||
'journey.studio.autoLayout': 'Auto layout', // en-fallback
|
||||
'journey.studio.export': 'Export', // en-fallback
|
||||
'journey.studio.day': 'DZIEŃ',
|
||||
'journey.studio.day': 'DZIEŃ {day}',
|
||||
'journey.studio.stations': 'Etapy',
|
||||
'journey.studio.peersHere': 'tutaj',
|
||||
'journey.studio.folioAuto': 'Automatycznie',
|
||||
@@ -470,7 +470,6 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.marks': 'Znaczniki',
|
||||
'journey.studio.dateMark': 'Data',
|
||||
'journey.studio.dayMark': 'Licznik dni',
|
||||
'journey.studio.dayWord': 'DZIEŃ',
|
||||
'journey.studio.coordsMark': 'Współrzędne',
|
||||
'journey.studio.coordsDms': 'Stopnie',
|
||||
'journey.studio.coordsDecimal': 'Dziesiętne',
|
||||
|
||||
@@ -310,7 +310,7 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.emptySpread': 'This spread is still empty', // en-fallback
|
||||
'journey.studio.autoLayout': 'Auto layout', // en-fallback
|
||||
'journey.studio.export': 'Export', // en-fallback
|
||||
'journey.studio.day': 'ДЕНЬ',
|
||||
'journey.studio.day': 'ДЕНЬ {day}',
|
||||
'journey.studio.stations': 'Остановки',
|
||||
'journey.studio.peersHere': 'здесь',
|
||||
'journey.studio.folioAuto': 'Автоматически',
|
||||
@@ -469,7 +469,6 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.marks': 'Метки',
|
||||
'journey.studio.dateMark': 'Дата',
|
||||
'journey.studio.dayMark': 'Счётчик дней',
|
||||
'journey.studio.dayWord': 'ДЕНЬ',
|
||||
'journey.studio.coordsMark': 'Координаты',
|
||||
'journey.studio.coordsDms': 'Градусы',
|
||||
'journey.studio.coordsDecimal': 'Десятичные',
|
||||
|
||||
@@ -303,7 +303,7 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.emptySpread': 'Táto dvojstrana je stále prázdna',
|
||||
'journey.studio.autoLayout': 'Automatické rozloženie',
|
||||
'journey.studio.export': 'Export',
|
||||
'journey.studio.day': 'DEŇ',
|
||||
'journey.studio.day': 'DEŇ {day}',
|
||||
'journey.studio.stations': 'Zastávky',
|
||||
'journey.studio.peersHere': 'tu',
|
||||
'journey.studio.folioAuto': 'Automaticky',
|
||||
@@ -462,7 +462,6 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.marks': 'Značky',
|
||||
'journey.studio.dateMark': 'Dátum',
|
||||
'journey.studio.dayMark': 'Počítadlo dní',
|
||||
'journey.studio.dayWord': 'DEŇ',
|
||||
'journey.studio.coordsMark': 'Súradnice',
|
||||
'journey.studio.coordsDms': 'Stupne',
|
||||
'journey.studio.coordsDecimal': 'Desatinné',
|
||||
|
||||
@@ -297,7 +297,7 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.emptySpread': 'This spread is still empty', // en-fallback
|
||||
'journey.studio.autoLayout': 'Auto layout', // en-fallback
|
||||
'journey.studio.export': 'Export', // en-fallback
|
||||
'journey.studio.day': 'DAG',
|
||||
'journey.studio.day': 'DAG {day}',
|
||||
'journey.studio.stations': 'Etapper',
|
||||
'journey.studio.peersHere': 'här',
|
||||
'journey.studio.folioAuto': 'Automatiskt',
|
||||
@@ -451,7 +451,6 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.marks': 'Märken',
|
||||
'journey.studio.dateMark': 'Datum',
|
||||
'journey.studio.dayMark': 'Dagräknare',
|
||||
'journey.studio.dayWord': 'DAG',
|
||||
'journey.studio.coordsMark': 'Koordinater',
|
||||
'journey.studio.coordsDms': 'Grader',
|
||||
'journey.studio.coordsDecimal': 'Decimal',
|
||||
|
||||
@@ -286,7 +286,7 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.emptySpread': 'สเปรดนี้ยังคงว่างเปล่า',
|
||||
'journey.studio.autoLayout': 'เค้าโครงอัตโนมัติ',
|
||||
'journey.studio.export': 'ส่งออก',
|
||||
'journey.studio.day': 'วัน',
|
||||
'journey.studio.day': 'วันที่ {day}',
|
||||
'journey.studio.stations': 'สถานี',
|
||||
'journey.studio.peersHere': 'ที่นี่',
|
||||
'journey.studio.folioAuto': 'อัตโนมัติ',
|
||||
@@ -436,7 +436,6 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.marks': 'เครื่องหมาย',
|
||||
'journey.studio.dateMark': 'วันที่',
|
||||
'journey.studio.dayMark': 'เคาน์เตอร์วัน',
|
||||
'journey.studio.dayWord': 'วัน',
|
||||
'journey.studio.coordsMark': 'พิกัด',
|
||||
'journey.studio.coordsDms': 'องศา',
|
||||
'journey.studio.coordsDecimal': 'ทศนิยม',
|
||||
|
||||
@@ -295,7 +295,7 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.emptySpread': 'This spread is still empty', // en-fallback
|
||||
'journey.studio.autoLayout': 'Auto layout', // en-fallback
|
||||
'journey.studio.export': 'Export', // en-fallback
|
||||
'journey.studio.day': 'GÜN',
|
||||
'journey.studio.day': '{day}. GÜN',
|
||||
'journey.studio.stations': 'Duraklar',
|
||||
'journey.studio.peersHere': 'burada',
|
||||
'journey.studio.folioAuto': 'Otomatik',
|
||||
@@ -452,7 +452,6 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.marks': 'İşaretler',
|
||||
'journey.studio.dateMark': 'Tarih',
|
||||
'journey.studio.dayMark': 'Gün sayacı',
|
||||
'journey.studio.dayWord': 'GÜN',
|
||||
'journey.studio.coordsMark': 'Koordinatlar',
|
||||
'journey.studio.coordsDms': 'Derece',
|
||||
'journey.studio.coordsDecimal': 'Ondalık',
|
||||
|
||||
@@ -311,7 +311,7 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.emptySpread': 'This spread is still empty', // en-fallback
|
||||
'journey.studio.autoLayout': 'Auto layout', // en-fallback
|
||||
'journey.studio.export': 'Export', // en-fallback
|
||||
'journey.studio.day': 'ДЕНЬ',
|
||||
'journey.studio.day': 'ДЕНЬ {day}',
|
||||
'journey.studio.stations': 'Зупинки',
|
||||
'journey.studio.peersHere': 'тут',
|
||||
'journey.studio.folioAuto': 'Автоматично',
|
||||
@@ -473,7 +473,6 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.marks': 'Позначки',
|
||||
'journey.studio.dateMark': 'Дата',
|
||||
'journey.studio.dayMark': 'Лічильник днів',
|
||||
'journey.studio.dayWord': 'ДЕНЬ',
|
||||
'journey.studio.coordsMark': 'Координати',
|
||||
'journey.studio.coordsDms': 'Градуси',
|
||||
'journey.studio.coordsDecimal': 'Десяткові',
|
||||
|
||||
@@ -291,7 +291,7 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.emptySpread': 'This spread is still empty', // en-fallback
|
||||
'journey.studio.autoLayout': 'Auto layout', // en-fallback
|
||||
'journey.studio.export': 'Export', // en-fallback
|
||||
'journey.studio.day': 'NGÀY',
|
||||
'journey.studio.day': 'NGÀY {day}',
|
||||
'journey.studio.stations': 'Chặng dừng',
|
||||
'journey.studio.peersHere': 'ở đây',
|
||||
'journey.studio.folioAuto': 'Tự động',
|
||||
@@ -443,7 +443,6 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.marks': 'Dấu',
|
||||
'journey.studio.dateMark': 'Ngày',
|
||||
'journey.studio.dayMark': 'Bộ đếm ngày',
|
||||
'journey.studio.dayWord': 'NGÀY',
|
||||
'journey.studio.coordsMark': 'Tọa độ',
|
||||
'journey.studio.coordsDms': 'Độ',
|
||||
'journey.studio.coordsDecimal': 'Thập phân',
|
||||
|
||||
@@ -284,7 +284,7 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.emptySpread': 'This spread is still empty', // en-fallback
|
||||
'journey.studio.autoLayout': 'Auto layout', // en-fallback
|
||||
'journey.studio.export': 'Export', // en-fallback
|
||||
'journey.studio.day': '第',
|
||||
'journey.studio.day': '第{day}天',
|
||||
'journey.studio.stations': '途經地',
|
||||
'journey.studio.peersHere': '在線',
|
||||
'journey.studio.folioAuto': '自動',
|
||||
@@ -435,7 +435,6 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.marks': '標記',
|
||||
'journey.studio.dateMark': '日期',
|
||||
'journey.studio.dayMark': '天數計數',
|
||||
'journey.studio.dayWord': 'DAY',
|
||||
'journey.studio.coordsMark': '座標',
|
||||
'journey.studio.coordsDms': '度分秒',
|
||||
'journey.studio.coordsDecimal': '十進位',
|
||||
|
||||
@@ -284,7 +284,7 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.emptySpread': 'This spread is still empty', // en-fallback
|
||||
'journey.studio.autoLayout': 'Auto layout', // en-fallback
|
||||
'journey.studio.export': 'Export', // en-fallback
|
||||
'journey.studio.day': '第',
|
||||
'journey.studio.day': '第{day}天',
|
||||
'journey.studio.stations': '途经地',
|
||||
'journey.studio.peersHere': '在线',
|
||||
'journey.studio.folioAuto': '自动',
|
||||
@@ -435,7 +435,6 @@ const journey: TranslationStrings = {
|
||||
'journey.studio.marks': '标记',
|
||||
'journey.studio.dateMark': '日期',
|
||||
'journey.studio.dayMark': '天数计数',
|
||||
'journey.studio.dayWord': 'DAY',
|
||||
'journey.studio.coordsMark': '坐标',
|
||||
'journey.studio.coordsDms': '度分秒',
|
||||
'journey.studio.coordsDecimal': '十进制',
|
||||
|
||||
Reference in New Issue
Block a user