mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-18 21:16:47 +00:00
fix(roadtrip): the two search actions stop cutting their labels in half
"Add manually" did not fit beside "Search" and rendered as "Add manu…", which is neither the label nor a shape anybody recognises. The button face now carries one short word, with the full sentence kept as its accessible name and its tooltip, so nothing is lost to a reader or a pointer. Every locale got its own short form rather than a clipped version of the long one: Selbst, A mano, Ručně, Elle, 手動. Below two hundred pixels the row drops both words instead of shortening them, and the two actions are their icons. The width is the row's own, measured, not the window's: this column is resizable, so it can be narrow on a wide screen and a media query would answer the wrong question. The search button also stops restating the progress. Its label used to grow into "Searching 3 of 12" while a run was on, which is the longest string in the panel and the very sentence the progress row directly underneath already prints next to the share as a figure. It keeps its word, disabled, with the spinner in front of it.
This commit is contained in:
@@ -1,7 +1,17 @@
|
||||
import React from 'react'
|
||||
import { describe, it, expect, vi } from 'vitest'
|
||||
import { afterEach, describe, it, expect, vi } from 'vitest'
|
||||
import { render, screen, within, fireEvent } from '@testing-library/react'
|
||||
import { TranslationProvider } from '../../i18n'
|
||||
|
||||
// jsdom reports every element as zero by side, so the row that decides whether the two
|
||||
// actions keep their labels can only be driven from here. Zero is what the component
|
||||
// reads as "not measured yet", which is also the default below.
|
||||
const { rowWidth } = vi.hoisted(() => ({ rowWidth: { value: 0 } }))
|
||||
vi.mock('../../hooks/useElementSize', () => ({
|
||||
useElementSize: () => ({ ref: () => {}, width: rowWidth.value, height: 0 }),
|
||||
}))
|
||||
afterEach(() => { rowWidth.value = 0 })
|
||||
|
||||
import RoadtripCorridorPanel from './RoadtripCorridorPanel'
|
||||
import type { CorridorPoi } from './useCorridorPois'
|
||||
import type { RoadtripCorridor } from './useRoadtripCorridor'
|
||||
@@ -275,11 +285,21 @@ describe('RoadtripCorridorPanel', () => {
|
||||
})
|
||||
|
||||
it('FE-ROADTRIP-PANEL-013: while searching it reports progress rather than sitting still', () => {
|
||||
rowWidth.value = 320
|
||||
const c = corridor({}, { loading: true, progress: { done: 3, total: 12 } })
|
||||
wrap(<RoadtripCorridorPanel corridor={c} routes={routes([day(1, 1)])} />)
|
||||
|
||||
expect(screen.getByRole('progressbar')).toHaveAttribute('aria-valuenow', '25')
|
||||
expect(screen.getByRole('button', { name: /3/ })).toBeDisabled()
|
||||
// The sentence and the share belong to the row of their own, once. The button used
|
||||
// to restate them, which made the longest label in the panel and was the one being
|
||||
// cut off; it keeps its word, and the spinner in front of it says the run is on.
|
||||
const bar = screen.getByRole('progressbar')
|
||||
expect(bar).toHaveAttribute('aria-valuenow', '25')
|
||||
expect(bar).toHaveTextContent('Searching 3 of 12')
|
||||
|
||||
const [searchButton] = searchRow()
|
||||
expect(searchButton).toHaveTextContent('Search')
|
||||
expect(within(searchButton).queryByText(/Searching/)).toBeNull()
|
||||
expect(searchButton).toBeDisabled()
|
||||
})
|
||||
|
||||
it('FE-ROADTRIP-PANEL-014: a partial answer says which stretches nobody looked at', () => {
|
||||
@@ -431,6 +451,52 @@ describe('RoadtripCorridorPanel', () => {
|
||||
expect(searchRow()).toHaveLength(1)
|
||||
})
|
||||
|
||||
it('FE-ROADTRIP-PANEL-029: a roomy row keeps both words, and the manual one is the short form', () => {
|
||||
rowWidth.value = 320
|
||||
wrap(
|
||||
<RoadtripCorridorPanel corridor={corridor()} routes={routes([day(1, 1)])} onAddPoi={vi.fn()} onAddManual={vi.fn()} />,
|
||||
)
|
||||
|
||||
const [searchButton, manual] = searchRow()
|
||||
expect(searchButton).toHaveTextContent('Search')
|
||||
// The face of the button is the one word that fits beside it; the sentence stays
|
||||
// as the name a reader and a tooltip get.
|
||||
expect(manual).toHaveTextContent('Manual')
|
||||
expect(manual).toHaveAttribute('aria-label', 'Add manually')
|
||||
})
|
||||
|
||||
it('FE-ROADTRIP-PANEL-030: a narrow row drops the words rather than cutting them short', () => {
|
||||
// "Add manu…" is neither the label nor a shape anybody recognises. Below the
|
||||
// threshold both actions are their icon, and both keep their full names.
|
||||
rowWidth.value = 150
|
||||
wrap(
|
||||
<RoadtripCorridorPanel corridor={corridor()} routes={routes([day(1, 1)])} onAddPoi={vi.fn()} onAddManual={vi.fn()} />,
|
||||
)
|
||||
|
||||
const [searchButton, manual] = searchRow()
|
||||
expect(searchButton).toHaveTextContent('')
|
||||
expect(manual).toHaveTextContent('')
|
||||
expect(searchButton).toHaveAttribute('aria-label', 'Search')
|
||||
expect(manual).toHaveAttribute('aria-label', 'Add manually')
|
||||
// Still one row of two halves, not a stack.
|
||||
expect(searchButton.className).toContain('flex-1')
|
||||
expect(manual.className).toContain('flex-1')
|
||||
})
|
||||
|
||||
it('FE-ROADTRIP-PANEL-031: a narrow row loses the words even while a search is running', () => {
|
||||
// The spinner replaces the magnifier, and there is still no text to cut off.
|
||||
rowWidth.value = 150
|
||||
const c = corridor({}, { loading: true, progress: { done: 3, total: 12 } })
|
||||
wrap(<RoadtripCorridorPanel corridor={c} routes={routes([day(1, 1)])} onAddPoi={vi.fn()} onAddManual={vi.fn()} />)
|
||||
|
||||
const [searchButton, manual] = searchRow()
|
||||
expect(searchButton).toHaveTextContent('')
|
||||
expect(manual).toHaveTextContent('')
|
||||
expect(searchButton).toHaveAttribute('aria-label', 'Search')
|
||||
// The progress row is where the sentence lives, whatever the panel's width.
|
||||
expect(screen.getByRole('progressbar')).toHaveTextContent('Searching 3 of 12')
|
||||
})
|
||||
|
||||
it('FE-ROADTRIP-PANEL-027: clicking a row brings that hit into view, and adding it does not', () => {
|
||||
const onFocusPoint = vi.fn()
|
||||
const onAddPoi = vi.fn()
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
import { useTranslation } from '../../i18n/TranslationContext'
|
||||
import { Tooltip } from '../shared/Tooltip'
|
||||
import EmptyState from '../shared/EmptyState'
|
||||
import { useElementSize } from '../../hooks/useElementSize'
|
||||
import { useSettingsStore } from '../../store/settingsStore'
|
||||
import { formatDistance } from '../../utils/units'
|
||||
import CustomSelect from '../shared/CustomSelect'
|
||||
@@ -55,6 +56,16 @@ interface RoadtripCorridorPanelProps {
|
||||
/** The steps worth offering: a household socket, a fast AC post, and the two DC tiers. */
|
||||
const KW_STEPS = [11, 22, 50, 150]
|
||||
|
||||
/**
|
||||
* Below this, the two actions at the foot of the search card are icons alone, in pixels.
|
||||
*
|
||||
* Measured from what they need rather than picked round: two buttons, an eight pixel gap
|
||||
* and their own padding leave each of them about ninety pixels for a fifteen pixel icon,
|
||||
* a gap and a word. "Search" and the shortest sensible word beside it fit that; a hair
|
||||
* under it and the first thing to go is the end of the longer word.
|
||||
*/
|
||||
const ICON_ONLY_BELOW_PX = 200
|
||||
|
||||
const SOCKET_LABEL: Record<string, string> = {
|
||||
type2: 'Type 2',
|
||||
type2_combo: 'CCS',
|
||||
@@ -301,6 +312,16 @@ export default function RoadtripCorridorPanel({
|
||||
* search from being there the next time somebody opens it.
|
||||
*/
|
||||
const [manualOpen, setManualOpen] = useState(false)
|
||||
/**
|
||||
* The row the two actions share, measured, because this column is resizable.
|
||||
*
|
||||
* A media query would ask about the window, which is the wrong question: the panel
|
||||
* can be narrow on a wide screen and the labels have to go by what the row itself
|
||||
* got. Zero means the row has not been measured yet, and that reads as roomy rather
|
||||
* than cramped so the labels do not flash away on the first paint.
|
||||
*/
|
||||
const actionRow = useElementSize<HTMLDivElement>()
|
||||
const iconOnly = actionRow.width > 0 && actionRow.width < ICON_ONLY_BELOW_PX
|
||||
|
||||
const dayOptions = routes.days.map(d => ({
|
||||
value: String(d.dayId),
|
||||
@@ -426,25 +447,29 @@ export default function RoadtripCorridorPanel({
|
||||
Two halves of one row, because the search finds most of what is out there and
|
||||
not all of it: a good share of the chargers standing at a junction are in
|
||||
nobody's OpenStreetMap extract. The second button is the way to those, and it
|
||||
sits beside the search rather than under it so neither is the afterthought. */}
|
||||
<div className="flex gap-2">
|
||||
sits beside the search rather than under it so neither is the afterthought.
|
||||
|
||||
Below `ICON_ONLY_BELOW_PX` the two drop their labels rather than shortening
|
||||
them. A truncated word is worse than no word: "Add manu…" is neither the
|
||||
label nor a shape you recognise, while the plus and the magnifier are both
|
||||
read at a glance and keep their full names for a pointer and a reader. */}
|
||||
<div ref={actionRow.ref} className="flex gap-2">
|
||||
<button
|
||||
type="button"
|
||||
onClick={search.search}
|
||||
disabled={!canSearch}
|
||||
aria-label={t('roadtrip.poi.search')}
|
||||
title={iconOnly ? t('roadtrip.poi.search') : undefined}
|
||||
className="flex h-[32px] min-w-0 flex-1 items-center justify-center gap-2 rounded-lg bg-accent text-body font-semibold text-accent-text transition-opacity disabled:opacity-50"
|
||||
>
|
||||
{search.loading
|
||||
? <RotateCw size={15} className="shrink-0 animate-spin" aria-hidden />
|
||||
: <Search size={15} strokeWidth={2} className="shrink-0" aria-hidden />}
|
||||
{/* The label grows into "Searching 3 of 12" while a run is on. Sharing the
|
||||
row it has to shorten rather than push its neighbour off the panel, and
|
||||
the panel is resizable down to a width where that matters. */}
|
||||
<span className="min-w-0 truncate">
|
||||
{search.loading
|
||||
? t('roadtrip.poi.searching', { done: search.progress.done, total: search.progress.total })
|
||||
: t('roadtrip.poi.search')}
|
||||
</span>
|
||||
{/* The word stays put while a run is on, and the spinner in front of it says
|
||||
the run is on. It used to become "Searching 3 of 12", which is both the
|
||||
longest label in the panel and the very sentence the progress row right
|
||||
underneath prints, next to the share as a figure. */}
|
||||
{iconOnly ? null : <span className="min-w-0 truncate">{t('roadtrip.poi.search')}</span>}
|
||||
</button>
|
||||
{/* The day is part of the offer: with no drive on the trip at all there is
|
||||
nowhere for a stop to go, and a dialog that can only be cancelled is worse
|
||||
@@ -453,10 +478,14 @@ export default function RoadtripCorridorPanel({
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setManualOpen(true)}
|
||||
className="flex h-[32px] min-w-0 flex-1 items-center justify-center gap-2 rounded-lg border border-edge bg-surface-card text-body font-semibold text-content transition-colors hover:bg-surface-hover disabled:opacity-50"
|
||||
// The full sentence is the accessible name and the tooltip; the face of
|
||||
// the button carries the one word that fits beside "Search".
|
||||
aria-label={t('roadtrip.poi.addManual')}
|
||||
title={t('roadtrip.poi.addManual')}
|
||||
className="flex h-[32px] min-w-0 flex-1 items-center justify-center gap-2 rounded-lg border border-edge bg-surface-card text-body font-semibold text-content transition-colors hover:bg-surface-hover"
|
||||
>
|
||||
<Plus size={15} strokeWidth={2.2} className="shrink-0" aria-hidden />
|
||||
<span className="min-w-0 truncate">{t('roadtrip.poi.addManual')}</span>
|
||||
{iconOnly ? null : <span className="min-w-0 truncate">{t('roadtrip.poi.addManualShort')}</span>}
|
||||
</button>
|
||||
) : null}
|
||||
</div>
|
||||
|
||||
@@ -196,6 +196,7 @@ const roadtrip: TranslationStrings = {
|
||||
'roadtrip.poi.alongRoute': 'بعد {distance}',
|
||||
'roadtrip.poi.clearResults': 'مسح النتائج',
|
||||
'roadtrip.poi.addManual': 'إضافة يدوية',
|
||||
'roadtrip.poi.addManualShort': 'يدوي',
|
||||
'roadtrip.poi.manualHint':
|
||||
'لا يجد البحث عن الأماكن كل محطة شحن أو وقود. ابحث عن واحدة بالاسم وحدّد موضعها في الرحلة.',
|
||||
'roadtrip.poi.addBetween': 'الإضافة بين محطتين',
|
||||
|
||||
@@ -201,6 +201,7 @@ const roadtrip: TranslationStrings = {
|
||||
'roadtrip.poi.alongRoute': 'após {distance}',
|
||||
'roadtrip.poi.clearResults': 'Limpar resultados',
|
||||
'roadtrip.poi.addManual': 'Adicionar manualmente',
|
||||
'roadtrip.poi.addManualShort': 'Manual',
|
||||
'roadtrip.poi.manualHint':
|
||||
'A busca de locais não encontra todos os pontos de recarga nem todos os postos. Procure um pelo nome e diga em que ponto do trajeto ele entra.',
|
||||
'roadtrip.poi.addBetween': 'Adicionar entre',
|
||||
|
||||
@@ -203,6 +203,7 @@ const roadtrip: TranslationStrings = {
|
||||
'roadtrip.poi.alongRoute': 'després de {distance}',
|
||||
'roadtrip.poi.clearResults': 'Esborra resultats',
|
||||
'roadtrip.poi.addManual': 'Afegeix manualment',
|
||||
'roadtrip.poi.addManualShort': 'Manual',
|
||||
'roadtrip.poi.manualHint':
|
||||
'La cerca de llocs no troba tots els punts de recàrrega ni totes les benzineres. Busca’n un pel nom i digues en quin punt del trajecte va.',
|
||||
'roadtrip.poi.addBetween': 'Afegeix entre',
|
||||
|
||||
@@ -199,6 +199,7 @@ const roadtrip: TranslationStrings = {
|
||||
'roadtrip.poi.alongRoute': 'po {distance}',
|
||||
'roadtrip.poi.clearResults': 'Vymazat výsledky',
|
||||
'roadtrip.poi.addManual': 'Přidat ručně',
|
||||
'roadtrip.poi.addManualShort': 'Ručně',
|
||||
'roadtrip.poi.manualHint':
|
||||
'Vyhledávání míst nenajde každou nabíječku nebo pumpu. Najděte ji podle názvu a určete, kam na cestě patří.',
|
||||
'roadtrip.poi.addBetween': 'Přidat mezi',
|
||||
|
||||
@@ -198,6 +198,7 @@ const roadtrip: TranslationStrings = {
|
||||
'roadtrip.poi.alongRoute': 'nach {distance}',
|
||||
'roadtrip.poi.clearResults': 'Ergebnisse löschen',
|
||||
'roadtrip.poi.addManual': 'Selbst hinzufügen',
|
||||
'roadtrip.poi.addManualShort': 'Selbst',
|
||||
'roadtrip.poi.manualHint':
|
||||
'Die Ortssuche findet nicht jede Ladesäule und nicht jede Tankstelle. Suche einen Ort per Name und lege fest, wo unterwegs er hingehört.',
|
||||
'roadtrip.poi.addBetween': 'Einfügen zwischen',
|
||||
|
||||
@@ -195,6 +195,7 @@ const roadtrip: TranslationStrings = {
|
||||
'roadtrip.poi.alongRoute': 'after {distance}',
|
||||
'roadtrip.poi.clearResults': 'Clear results',
|
||||
'roadtrip.poi.addManual': 'Add manually',
|
||||
'roadtrip.poi.addManualShort': 'Manual',
|
||||
'roadtrip.poi.manualHint':
|
||||
'The place search does not find every charger or pump. Look one up by name and say where on the drive it goes.',
|
||||
'roadtrip.poi.addBetween': 'Add between',
|
||||
|
||||
@@ -202,6 +202,7 @@ const roadtrip: TranslationStrings = {
|
||||
'roadtrip.poi.alongRoute': 'tras {distance}',
|
||||
'roadtrip.poi.clearResults': 'Borrar resultados',
|
||||
'roadtrip.poi.addManual': 'Añadir a mano',
|
||||
'roadtrip.poi.addManualShort': 'A mano',
|
||||
'roadtrip.poi.manualHint':
|
||||
'La búsqueda de lugares no encuentra todos los puntos de recarga ni todas las gasolineras. Busca uno por su nombre e indica en qué punto del recorrido va.',
|
||||
'roadtrip.poi.addBetween': 'Añadir entre',
|
||||
|
||||
@@ -202,6 +202,7 @@ const roadtrip: TranslationStrings = {
|
||||
'roadtrip.poi.alongRoute': 'après {distance}',
|
||||
'roadtrip.poi.clearResults': 'Effacer les résultats',
|
||||
'roadtrip.poi.addManual': 'Ajouter manuellement',
|
||||
'roadtrip.poi.addManualShort': 'Manuel',
|
||||
'roadtrip.poi.manualHint':
|
||||
'La recherche de lieux ne trouve pas toutes les bornes ni toutes les stations-service. Cherchez-en une par son nom et indiquez où elle se place sur le trajet.',
|
||||
'roadtrip.poi.addBetween': 'Ajouter entre',
|
||||
|
||||
@@ -204,6 +204,7 @@ const roadtrip: TranslationStrings = {
|
||||
'roadtrip.poi.alongRoute': 'μετά από {distance}',
|
||||
'roadtrip.poi.clearResults': 'Καθαρισμός αποτελεσμάτων',
|
||||
'roadtrip.poi.addManual': 'Χειροκίνητη προσθήκη',
|
||||
'roadtrip.poi.addManualShort': 'Χειροκίνητα',
|
||||
'roadtrip.poi.manualHint':
|
||||
'Η αναζήτηση τοποθεσιών δεν βρίσκει κάθε φορτιστή ή πρατήριο καυσίμων. Βρείτε ένα με το όνομά του και δηλώστε πού μπαίνει στη διαδρομή.',
|
||||
'roadtrip.poi.addBetween': 'Προσθήκη ανάμεσα',
|
||||
|
||||
@@ -200,6 +200,7 @@ const roadtrip: TranslationStrings = {
|
||||
'roadtrip.poi.alongRoute': '{distance} után',
|
||||
'roadtrip.poi.clearResults': 'Találatok törlése',
|
||||
'roadtrip.poi.addManual': 'Hozzáadás kézzel',
|
||||
'roadtrip.poi.addManualShort': 'Kézzel',
|
||||
'roadtrip.poi.manualHint':
|
||||
'A helykeresés nem talál meg minden töltőt vagy benzinkutat. Keresd meg név szerint, és add meg, hová kerüljön az úton.',
|
||||
'roadtrip.poi.addBetween': 'Beszúrás két megálló közé',
|
||||
|
||||
@@ -202,6 +202,7 @@ const roadtrip: TranslationStrings = {
|
||||
'roadtrip.poi.alongRoute': 'setelah {distance}',
|
||||
'roadtrip.poi.clearResults': 'Hapus hasil',
|
||||
'roadtrip.poi.addManual': 'Tambah manual',
|
||||
'roadtrip.poi.addManualShort': 'Manual',
|
||||
'roadtrip.poi.manualHint':
|
||||
'Pencarian tempat tidak menemukan setiap pengisian daya atau pompa bahan bakar. Cari satu menurut nama dan tentukan di bagian perjalanan mana ia ditempatkan.',
|
||||
'roadtrip.poi.addBetween': 'Tambahkan di antara',
|
||||
|
||||
@@ -202,6 +202,7 @@ const roadtrip: TranslationStrings = {
|
||||
'roadtrip.poi.alongRoute': 'dopo {distance}',
|
||||
'roadtrip.poi.clearResults': 'Svuota risultati',
|
||||
'roadtrip.poi.addManual': 'Aggiungi a mano',
|
||||
'roadtrip.poi.addManualShort': 'A mano',
|
||||
'roadtrip.poi.manualHint':
|
||||
'La ricerca dei luoghi non trova ogni colonnina o distributore. Cercane uno per nome e indica dove si inserisce nel viaggio.',
|
||||
'roadtrip.poi.addBetween': 'Inserisci tra',
|
||||
|
||||
@@ -199,6 +199,7 @@ const roadtrip: TranslationStrings = {
|
||||
'roadtrip.poi.alongRoute': '{distance} 地点',
|
||||
'roadtrip.poi.clearResults': '結果を消去',
|
||||
'roadtrip.poi.addManual': '手動で追加',
|
||||
'roadtrip.poi.addManualShort': '手動',
|
||||
'roadtrip.poi.manualHint':
|
||||
'場所の検索では、すべての充電スポットや給油所は見つかりません。名前で探して、道中のどこに入れるかを指定してください。',
|
||||
'roadtrip.poi.addBetween': '追加する区間',
|
||||
|
||||
@@ -198,6 +198,7 @@ const roadtrip: TranslationStrings = {
|
||||
'roadtrip.poi.alongRoute': '{distance} 지점',
|
||||
'roadtrip.poi.clearResults': '결과 지우기',
|
||||
'roadtrip.poi.addManual': '직접 추가',
|
||||
'roadtrip.poi.addManualShort': '직접',
|
||||
'roadtrip.poi.manualHint': '장소 검색이 모든 충전소나 주유소를 찾아내지는 못합니다. 이름으로 직접 찾아 주행 중 어디에 들어갈지 지정하세요.',
|
||||
'roadtrip.poi.addBetween': '사이에 추가',
|
||||
'roadtrip.poi.manualOffRoute': '경로에서 {distance} 떨어져 있으니 어느 구간에 속하는지 확인하세요.',
|
||||
|
||||
@@ -202,6 +202,7 @@ const roadtrip: TranslationStrings = {
|
||||
'roadtrip.poi.alongRoute': 'na {distance}',
|
||||
'roadtrip.poi.clearResults': 'Resultaten wissen',
|
||||
'roadtrip.poi.addManual': 'Handmatig toevoegen',
|
||||
'roadtrip.poi.addManualShort': 'Handmatig',
|
||||
'roadtrip.poi.manualHint':
|
||||
'De plaatszoekfunctie vindt niet elk laadpunt of tankstation. Zoek er zelf een op naam en geef aan waar in de rit hij hoort.',
|
||||
'roadtrip.poi.addBetween': 'Toevoegen tussen',
|
||||
|
||||
@@ -200,6 +200,7 @@ const roadtrip: TranslationStrings = {
|
||||
'roadtrip.poi.alongRoute': 'po {distance}',
|
||||
'roadtrip.poi.clearResults': 'Wyczyść wyniki',
|
||||
'roadtrip.poi.addManual': 'Dodaj ręcznie',
|
||||
'roadtrip.poi.addManualShort': 'Ręcznie',
|
||||
'roadtrip.poi.manualHint':
|
||||
'Wyszukiwanie miejsc nie znajdzie każdej ładowarki ani stacji paliw. Wyszukaj ją po nazwie i wskaż, gdzie na trasie ma się znaleźć.',
|
||||
'roadtrip.poi.addBetween': 'Dodaj między',
|
||||
|
||||
@@ -202,6 +202,7 @@ const roadtrip: TranslationStrings = {
|
||||
'roadtrip.poi.alongRoute': 'через {distance}',
|
||||
'roadtrip.poi.clearResults': 'Очистить результаты',
|
||||
'roadtrip.poi.addManual': 'Добавить вручную',
|
||||
'roadtrip.poi.addManualShort': 'Вручную',
|
||||
'roadtrip.poi.manualHint':
|
||||
'Поиск мест находит не каждую зарядку или заправку. Найдите место по названию и укажите, куда в поездке его поставить.',
|
||||
'roadtrip.poi.addBetween': 'Добавить между',
|
||||
|
||||
@@ -199,6 +199,7 @@ const roadtrip: TranslationStrings = {
|
||||
'roadtrip.poi.alongRoute': 'efter {distance}',
|
||||
'roadtrip.poi.clearResults': 'Rensa träffar',
|
||||
'roadtrip.poi.addManual': 'Lägg till manuellt',
|
||||
'roadtrip.poi.addManualShort': 'Manuellt',
|
||||
'roadtrip.poi.manualHint':
|
||||
'Platssökningen hittar inte alla laddare eller bensinstationer. Sök upp en på namn och ange var i körningen den ska ligga.',
|
||||
'roadtrip.poi.addBetween': 'Lägg till mellan',
|
||||
|
||||
@@ -201,6 +201,7 @@ const roadtrip: TranslationStrings = {
|
||||
'roadtrip.poi.alongRoute': '{distance} sonra',
|
||||
'roadtrip.poi.clearResults': 'Sonuçları temizle',
|
||||
'roadtrip.poi.addManual': 'Elle ekle',
|
||||
'roadtrip.poi.addManualShort': 'Elle',
|
||||
'roadtrip.poi.manualHint':
|
||||
'Yer araması her şarj noktasını veya benzin istasyonunu bulamaz. Adıyla arayın ve sürüşün neresine gireceğini söyleyin.',
|
||||
'roadtrip.poi.addBetween': 'Araya ekle',
|
||||
|
||||
@@ -201,6 +201,7 @@ const roadtrip: TranslationStrings = {
|
||||
'roadtrip.poi.alongRoute': 'через {distance}',
|
||||
'roadtrip.poi.clearResults': 'Очистити результати',
|
||||
'roadtrip.poi.addManual': 'Додати вручну',
|
||||
'roadtrip.poi.addManualShort': 'Вручну',
|
||||
'roadtrip.poi.manualHint':
|
||||
'Пошук місць знаходить не кожну зарядку чи заправку. Знайдіть потрібну за назвою та вкажіть, де в дорозі вона має бути.',
|
||||
'roadtrip.poi.addBetween': 'Додати між',
|
||||
|
||||
@@ -200,6 +200,7 @@ const roadtrip: TranslationStrings = {
|
||||
'roadtrip.poi.alongRoute': 'sau {distance}',
|
||||
'roadtrip.poi.clearResults': 'Xóa kết quả',
|
||||
'roadtrip.poi.addManual': 'Thêm thủ công',
|
||||
'roadtrip.poi.addManualShort': 'Thủ công',
|
||||
'roadtrip.poi.manualHint':
|
||||
'Tìm kiếm địa điểm không tìm ra mọi trạm sạc hay trạm xăng. Hãy tra theo tên và cho biết nó nằm ở đâu trên hành trình.',
|
||||
'roadtrip.poi.addBetween': 'Thêm vào giữa',
|
||||
|
||||
@@ -189,6 +189,7 @@ const roadtrip: TranslationStrings = {
|
||||
'roadtrip.poi.alongRoute': '{distance} 處',
|
||||
'roadtrip.poi.clearResults': '清除結果',
|
||||
'roadtrip.poi.addManual': '手動新增',
|
||||
'roadtrip.poi.addManualShort': '手動',
|
||||
'roadtrip.poi.manualHint': '地點搜尋不一定能找到每個充電站或加油站。請自行用名稱搜尋,並指定它在行程中的位置。',
|
||||
'roadtrip.poi.addBetween': '新增於兩站之間',
|
||||
'roadtrip.poi.manualOffRoute': '偏離路線 {distance},請確認它屬於哪一段。',
|
||||
|
||||
@@ -189,6 +189,7 @@ const roadtrip: TranslationStrings = {
|
||||
'roadtrip.poi.alongRoute': '{distance} 处',
|
||||
'roadtrip.poi.clearResults': '清除结果',
|
||||
'roadtrip.poi.addManual': '手动添加',
|
||||
'roadtrip.poi.addManualShort': '手动',
|
||||
'roadtrip.poi.manualHint': '地点搜索不会找到所有充电站或加油站。按名称自行搜索,并指定它在行程中的位置。',
|
||||
'roadtrip.poi.addBetween': '添加到两站之间',
|
||||
'roadtrip.poi.manualOffRoute': '偏离路线 {distance},请确认它属于哪个路段。',
|
||||
|
||||
Reference in New Issue
Block a user