Link to a swimlane or a list, the way you can link to a card.

A card has had an address since there has been a card route. A swimlane and a
list had none: "the Backlog list of this board" could only be sent as "open
this board and scroll down". Worse, List.absoluteUrl() answered with the URL
of whichever CARD the cache returned first for that list, so the one place
that did offer a list link - listMorePopup - showed a card's address, and an
empty box for an empty list.

Both have their own now:

  /b/<boardId>/<slug>/swimlane/<swimlaneId>
  /b/<boardId>/<slug>/list/<listId>

FIVE segments against the card route's four, which is the whole reason the
three can coexist: a card URL cannot match these and these cannot match a
card. A guard checks all nine combinations, because losing a segment would
silently turn a link to a list into a link to a card called "list". The kind
is a word in the path rather than a query parameter - it is part of what the
address names, and a reader can see which is which. config/router.js
registers the routes from the same constants the links are built from, so the
two cannot disagree about the path.

Following one brings the thing into view. The route cannot do that: it runs
before the board has rendered, and on a board that is already open it runs
without re-creating anything, so at that moment there is nothing on screen to
scroll. It names what to reveal in a Session value and the board body reveals
it, WAITING for the element rather than assuming it - swimlanes and lists
arrive as their subscriptions do and a large board renders in more than one
pass, so a single look on the next tick finds nothing on a cold load. It
gives up after a few seconds rather than spinning: a link to a list that was
archived names an element that is never going to exist, and the board is
still the right place to have landed.

The Session value is cleared when acted on AND when given up on, so it is a
one-shot instruction about the address you followed rather than a standing
order that re-scrolls on every later render - and cleared BEFORE the scroll,
because scrollIntoView can re-enter the autorun through the reactive read.
Every other board route clears it too: without that, opening a card after a
list link would scroll the board away from the card it had just opened.

The element ids are the ones the templates already carry, held as a map and
not derived by a rule. Deriving one name from another is how
allBoardsMultiselectionSidebar happened, and this failure is silent - nothing
is found and nothing is reported - so a guard checks each id against the
markup that draws it.

All three are copied the same way, from the FIRST row of the hamburger menu,
with the link icon and the name beside it. The card carried this as an icon in
its title header named only by a tooltip, which is the one place a name cannot
be read without hovering; that button is gone, and so are its handler and the
"Copied" tooltip only it used - a handler for markup that no longer exists is
dead code that reads as a working feature.

The copy row sits ABOVE every permission check in those menus. Copying an
address is reading, not editing: somebody who may only read the board can
still tell a colleague which list they mean, while everything else in those
menus changes the board and stays guarded. It copies absoluteUrl(), because
what lands in the clipboard is pasted into a chat and a relative path is only
a link inside this page.

copy-link-to-clipboard is added to all 147 language files, in the same
position in each. 119 are really translated, each derived from that
language's OWN existing copy-strings rather than invented. The 16 that keep
the English placeholder are the ones whose existing copy-strings are already
in the wrong language - Romanian holding Italian, Esperanto holding Spanish,
Hindi holding Gujarati - where deriving from them would only spread the
error; the en_* variants are English by design.

docs/Design/Page/Header.md is written at last. Twenty-seven comments have
been pointing at it since the header restructure began and it had never
existed, so every one of them was a dead reference.

Thanks to xet7 !
This commit is contained in:
Lauri Ojansivu committed 2026-07-31 16:04:18 +03:00
1 parent 4bf3dab1c5
commit e755b60b37
165 files changed
+1173 -33

No files matched your search

+37
View File
@@ -265,6 +265,43 @@ browser build to verify).
This release adds the following new features:
<details>
<summary><a href="https://github.com/wekan/wekan/commit/HASH">A swimlane, a list and a card can each be linked, and the link lands on the thing it names</a>. Thanks to xet7.</summary>
A card has had an address since there has been a card route. A swimlane and a
list had none, so "the Backlog list of this board" could only be sent as "open
this board and scroll down" — and `List.absoluteUrl()` answered with the URL of
whichever CARD the cache returned first for that list, so the one place that did
offer a list link showed a card's address, and an empty box for an empty list.
Both have their own now — `/b/<board>/<slug>/swimlane/<id>` and
`/b/<board>/<slug>/list/<id>`. Five segments against the card route's four,
which is what keeps the three apart: a card URL cannot match these and these
cannot match a card.
Following one brings the thing into view. The route cannot scroll — it runs
before the board has rendered, and on a board that is already open it runs
without re-creating anything — so it names what to reveal and the board body
reveals it once the element exists, waiting for it rather than assuming it,
because a large board renders in more than one pass. It gives up after a few
seconds instead of spinning: a link to a list that was archived names an element
that is never going to exist, and the board is still the right place to have
landed. The revealed swimlane or list gets a brief outline, because a scroll
that lands mid-board gives no sign of which of the things now on screen the link
was about.
All three are copied the same way, from the first row of the hamburger menu,
with the link icon and the name beside it. The card carried this as an icon in
its title header named only by a tooltip — the one place a name cannot be read
without hovering — and that button is gone, along with its handler and the
"Copied" tooltip only it used.
The copy row sits above every permission check in those menus: copying an
address is reading, not editing, and somebody who may only read the board can
still tell a colleague which list they mean.
</details>
<details>
<summary><a href="https://github.com/wekan/wekan/commit/6051a4368">All Boards keeps its four controls in the header bar, and drops the hamburger that only led to them</a>. Thanks to xet7.</summary>
+13
View File
@@ -9,6 +9,8 @@ import {
import '/client/lib/dragscrollTouch';
import '/client/lib/dragDropTouch';
import { boardConverter } from '/client/lib/boardConverter';
// Bring the swimlane or list a link named into view, once it has rendered.
import { watchBoardItemReveals } from '/client/lib/revealBoardItem';
import { formatDateByUserPreference } from '/imports/lib/dateUtils';
import { toFullCalendarFirstDay } from '/client/lib/calendarFirstDay';
import { weekNumberByFirstDay } from '/models/lib/weekStart';
@@ -289,6 +291,11 @@ Template.boardBody.onRendered(function () {
// Initialize user settings (zoom and mobile mode)
Utils.initializeUserSettings();
// A link to a swimlane or a list has to end with that thing on screen. The
// route can only NAME it - it runs before this has rendered - so the reveal
// waits here for the element to exist. client/lib/revealBoardItem.js
this.boardItemReveals = watchBoardItemReveals();
// Detect iPhone devices and add class for better CSS targeting
const isIPhone = /iPhone|iPod/.test(navigator.userAgent);
if (isIPhone) {
@@ -672,6 +679,12 @@ Template.boardBody.onRendered(function () {
});
Template.boardBody.onDestroyed(function () {
// The reveal watcher owns a Tracker computation and a retry interval, and
// neither stops on its own when this template goes.
if (this.boardItemReveals) {
this.boardItemReveals.stop();
this.boardItemReveals = null;
}
if (BoardBody === this) {
BoardBody = null;
}
+12 -16
View File
@@ -24,17 +24,9 @@ template(name="cardDetails")
a.fa.fa-window-maximize.maximize-card-details.js-maximize-card-details(title="{{_ 'maximize-card'}}")
a.card-details-menu.js-open-card-details-menu(title="{{_ 'cardDetailsActionsPopup-title'}}")
i.fa.fa-bars
a.card-copy-button.js-copy-link(
id="cardURL_copy"
title="{{_ 'copy-card-link-to-clipboard'}}"
href="{{ originRelativeUrl }}"
)
span.emoji-icon
i.fa.fa-link
if canModifyCard
span.card-drag-handle.js-card-drag-handle(title="Drag card")
i.fa.fa-arrows
span.copied-tooltip {{_ 'copied'}}
else
a.close-card-details.js-close-card-details(title="{{_ 'close-card'}}")
i.fa.fa-times-thin
@@ -53,14 +45,6 @@ template(name="cardDetails")
a.fa.fa-window-maximize.maximize-card-details.js-maximize-card-details(title="{{_ 'maximize-card'}}")
a.card-details-menu-mobile-web.js-open-card-details-menu(title="{{_ 'cardDetailsActionsPopup-title'}}")
i.fa.fa-bars
a.card-copy-mobile-button.js-copy-link(
id="cardURL_copy"
title="{{_ 'copy-card-link-to-clipboard'}}"
href="{{ originRelativeUrl }}"
)
span.emoji-icon
i.fa.fa-link
span.copied-tooltip {{_ 'copied'}}
if canModifyCard
if currentBoard.allowsDueComplete
a.card-details-complete-toggle.js-toggle-due-complete(title="{{#if getDueComplete}}{{_ 'card-mark-incomplete'}}{{else}}{{_ 'card-mark-complete'}}{{/if}}")
@@ -786,6 +770,18 @@ template(name="editCardSortOrderForm")
template(name="cardDetailsActionsPopup")
if currentUser
//- Copy link, first, and named - the card's header carried this as an icon
with only a tooltip, which is the one place a name cannot be read without
hovering. It is here now, beside the swimlane's and the list's, so all
three are copied the same way from the same kind of menu.
docs/Design/Page/Board-Item-Links.md
ul.pop-over-list
li
a.js-copy-card-link
i.fa.fa-link
| {{_ 'copy-link-to-clipboard'}}
span.copied-tooltip {{_ 'copied'}}
hr
ul.pop-over-list
li
a.js-toggle-watch-card
+13 -9
View File
@@ -961,15 +961,6 @@ Template.cardDetails.events({
Utils.goBoardId(boardId);
}
},
'click .js-copy-link'(event, tpl) {
event.preventDefault();
const card = Template.currentData();
const url = card.absoluteUrl();
const promise = Utils.copyTextToClipboard(url);
const $tooltip = tpl.$('.card-details-header .copied-tooltip');
Utils.showCopied(promise, $tooltip);
},
'change .js-date-format-selector'(event) {
const dateFormat = event.target.value;
if (Meteor.userId()) {
@@ -1595,6 +1586,19 @@ Template.cardDetailsActionsPopup.helpers({
});
Template.cardDetailsActionsPopup.events({
// Copy the card's address. This was an icon in the card's header with only a
// tooltip to name it - the one place a name cannot be read without hovering -
// and it is here now beside the swimlane's and the list's, so all three are
// copied the same way from the same kind of menu.
// docs/Design/Page/Board-Item-Links.md
'click .js-copy-card-link'(event, tpl) {
event.preventDefault();
const card = Template.currentData();
if (!card) return;
const url = card.absoluteUrl();
if (!url) return;
Utils.showCopied(Utils.copyTextToClipboard(url), tpl.$('.copied-tooltip'));
},
'click .js-export-card': Popup.open('exportCard'),
'click .js-members': Popup.open('cardMembers'),
'click .js-assignees': Popup.open('cardAssignees'),
+14 -2
View File
@@ -128,6 +128,16 @@ template(name="editListTitleForm")
i.fa.fa-times-thin
template(name="listActionPopup")
//- Copy link, FIRST and above every permission check - see the swimlane
popup: copying an address is reading, not editing.
models/lib/boardItemUrl.js, docs/Design/Page/Board-Item-Links.md
ul.pop-over-list
li: a.js-copy-list-link
i.fa.fa-link
span
| {{_ 'copy-link-to-clipboard'}}
span.copied-tooltip {{_ 'copied'}}
hr
unless currentUser.isReadOnly
unless currentUser.isReadAssignedOnly
ul.pop-over-list
@@ -226,8 +236,10 @@ template(name="listMorePopup")
= ' '
i.fa(class="{{#if currentBoard.isPublic}}fa-globe{{else}}fa-lock{{/if}}")
//- #6459: was {{ rootUrl }}, a helper that does not exist anywhere, so the
//- link input was always empty. absoluteUrl resolves a URL via a card on
//- this list.
//- link input was always empty. absoluteUrl was then resolved through a
//- CARD of this list, so the box showed a card's address - and nothing at
//- all for an empty list. A list has its own address now.
//- models/lib/boardItemUrl.js
input.inline-input(type="text" readonly value="{{ absoluteUrl }}")
| {{_ 'added'}}
span.date(title=list.createdAt) {{ displayDate createdAt 'LLL' }}
+13
View File
@@ -278,6 +278,19 @@ Template.listActionPopup.helpers({
});
Template.listActionPopup.events({
// Copy the list's own address. `absoluteUrl` so what lands in the
// clipboard can be pasted anywhere - a relative path is only a link inside
// this page. The popup stays open long enough to show "Copied"; it is the
// confirmation, and a menu that vanishes the instant you click leaves you
// wondering whether anything happened. models/lib/boardItemUrl.js
'click .js-copy-list-link'(event, tpl) {
event.preventDefault();
const list = Template.currentData();
if (!list) return;
const url = list.absoluteUrl();
if (!url) return;
Utils.showCopied(Utils.copyTextToClipboard(url), tpl.$('.copied-tooltip'));
},
'click .js-list-subscribe'() {},
'click .js-add-card.list-header-plus-top'(event) {
const listDom = $(`#js-list-${this._id}`)[0];
@@ -55,6 +55,18 @@ template(name="editSwimlaneTitleForm")
template(name="swimlaneActionPopup")
if currentUser
//- Copy link, FIRST and above every permission check: a swimlane has an
address now, and copying it is reading, not editing - somebody who may
only read the board may still tell a colleague which swimlane they mean.
The rows below are all guarded because they change the board.
models/lib/boardItemUrl.js, docs/Design/Page/Board-Item-Links.md
ul.pop-over-list
li: a.js-copy-swimlane-link
i.fa.fa-link
span
| {{_ 'copy-link-to-clipboard'}}
span.copied-tooltip {{_ 'copied'}}
hr
unless currentUser.isCommentOnly
unless currentUser.isReadOnly
unless currentUser.isReadAssignedOnly
@@ -98,6 +98,19 @@ Template.editSwimlaneTitleForm.helpers({
});
Template.swimlaneActionPopup.events({
// Copy the swimlane's own address. `absoluteUrl` so what lands in the
// clipboard can be pasted anywhere - a relative path is only a link inside
// this page. The popup stays open long enough to show "Copied"; it is the
// confirmation, and a menu that vanishes the instant you click leaves you
// wondering whether anything happened. models/lib/boardItemUrl.js
'click .js-copy-swimlane-link'(event, tpl) {
event.preventDefault();
const swimlane = Template.currentData();
if (!swimlane) return;
const url = swimlane.absoluteUrl();
if (!url) return;
Utils.showCopied(Utils.copyTextToClipboard(url), tpl.$('.copied-tooltip'));
},
'click .js-add-swimlane': Popup.open('swimlaneAdd'),
'click .js-add-list-from-swimlane': Popup.open('addList'),
'click .js-set-swimlane-color': Popup.open('setSwimlaneColor'),
+28
View File
@@ -399,3 +399,31 @@ body.swimlane-resizing-active {
body.swimlane-resizing-active * {
cursor: row-resize !important;
}
/* The swimlane or list a link named, for a moment after it is scrolled to.
A scroll that lands mid-board gives no sign of WHICH of the things now on
screen the link was about; this says so and then gets out of the way. The
class is removed after the animation by client/lib/revealBoardItem.js, so
nothing is left highlighted for the rest of the session.
`outline`, not `border` or `box-shadow`: it is drawn outside the box and so
moves neither the swimlane's rows nor the list's cards by a pixel. */
.is-revealed {
outline: 3px solid #2980b9;
outline-offset: -3px;
animation: wekan-reveal-fade 2s ease-out forwards;
}
@keyframes wekan-reveal-fade {
0% { outline-color: #2980b9; }
70% { outline-color: #2980b9; }
100% { outline-color: transparent; }
}
/* Somebody who asked not to be animated gets the outline without the fade -
the point is to say which one, and that does not need movement. */
@media (prefers-reduced-motion: reduce) {
.is-revealed {
animation: none;
}
}
+94
View File
@@ -0,0 +1,94 @@
import { Session } from 'meteor/session';
import { Tracker } from 'meteor/tracker';
import {
REVEAL_KINDS,
REVEAL_TARGETS,
revealElementId,
} from '/models/lib/revealBoardItem';
// Bring the swimlane or list a link named into view.
//
// The route names it in a Session value (config/router.js) because the route
// runs before the board has rendered, and on a board that is already open it
// runs without re-creating anything - so there is nothing to scroll at the
// moment the address changes.
//
// This waits for the element instead of assuming it. Swimlanes and lists arrive
// as their subscriptions do, and a board with many of them renders in more than
// one pass, so a single look on the next tick finds nothing on a cold load. It
// retries on a short interval and gives up after a few seconds rather than
// spinning forever: a link to a list that was archived or deleted names an
// element that is never going to exist, and the board is still the right place
// to have landed.
//
// The Session value is cleared as soon as it is acted on - or given up on - so
// it is a one-shot instruction about the address you followed, not a standing
// order that re-scrolls the board every time something re-renders.
//
// docs/Design/Page/Board-Item-Links.md
const RETRY_MS = 100;
const GIVE_UP_MS = 8000;
function scrollIntoView(element) {
if (!element) return;
// `center` on both axes: a swimlane is a row and a list is a column, so one
// of the two is always the axis that matters and neither kind knows which.
if (typeof element.scrollIntoView === 'function') {
element.scrollIntoView({ block: 'center', inline: 'center', behavior: 'smooth' });
}
// A brief highlight, because a scroll that lands mid-board gives no sign of
// WHICH of the things on screen the link was about. The class removes itself;
// the animation is in the stylesheet.
element.classList.add('is-revealed');
setTimeout(() => element.classList.remove('is-revealed'), 2000);
}
// Watch one kind. Returns the Tracker computation so a caller can stop it.
function watchKind(kind) {
const { sessionKey } = REVEAL_TARGETS[kind];
let timer = null;
const stopTimer = () => {
if (timer) { clearInterval(timer); timer = null; }
};
const computation = Tracker.autorun(() => {
const id = Session.get(sessionKey);
stopTimer();
const elementId = revealElementId(kind, id);
if (!elementId) return;
const started = Date.now();
const attempt = () => {
const element = document.getElementById(elementId);
if (element) {
stopTimer();
// Cleared first: scrollIntoView can re-enter this autorun through the
// reactive Session read, and clearing before scrolling makes the second
// pass a no-op rather than a second scroll.
Session.set(sessionKey, null);
scrollIntoView(element);
return;
}
if (Date.now() - started > GIVE_UP_MS) {
// Archived, deleted, or on a board this user cannot see all of. The
// board is still the right place to have landed, so this stops quietly.
stopTimer();
Session.set(sessionKey, null);
}
};
// Once now - on a board that is already open the element is already there,
// and waiting a tick to find it makes the jump visibly late.
attempt();
if (Session.get(sessionKey)) timer = setInterval(attempt, RETRY_MS);
});
return { stop() { stopTimer(); computation.stop(); } };
}
// Start watching every kind. Called from the board body once it has rendered.
export function watchBoardItemReveals() {
const watchers = REVEAL_KINDS.map(watchKind);
return { stop() { watchers.forEach(w => w.stop()); } };
}
+57
View File
@@ -7,6 +7,9 @@ import { ReactiveCache } from '/imports/reactiveCache';
import { decideSandstormAutoOpen } from '/models/lib/sandstormAutoOpen';
import { cardBoardRedirectTarget } from '/models/lib/cardLinkRedirect';
import Settings from '/models/settings';
// The swimlane and list routes, whose paths are built beside the URLs they
// match so the two cannot disagree. models/lib/boardItemUrl.js
import { SWIMLANE_ROUTE_PATH, LIST_ROUTE_PATH } from '/models/lib/boardItemUrl';
import { EscapeActions } from '/client/lib/escapeActions';
import { Filter } from '/client/lib/filter';
import { Utils } from '/client/lib/utils';
@@ -392,11 +395,63 @@ function maybeRedirectMovedCard(urlBoardId, cardId) {
movedCardCheck = { computation, sub };
}
// A swimlane and a list have an address of their own, so either can be linked
// the way a card can. FIVE segments against the card route's four, which is what
// keeps the three apart: a card route cannot match these and these cannot match
// a card. models/lib/boardItemUrl.js
//
// The route cannot scroll anything: it runs before the board has rendered, and
// on a board that is already open it runs without re-creating anything. So it
// names what to REVEAL in a Session value, and the board body reveals it once
// the element exists. docs/Design/Page/Board-Item-Links.md
FlowRouter.route(SWIMLANE_ROUTE_PATH, {
name: 'swimlane',
action(params) {
Session.set('currentBoard', params.boardId);
Session.set('currentCard', null);
Session.set('popupCardId', null);
Session.set('popupCardBoardId', null);
Session.set('revealSwimlaneId', params.swimlaneId);
Session.set('revealListId', null);
Utils.manageCustomUI();
Utils.manageMatomo();
this.render('defaultLayout', {
content: 'board',
});
},
});
FlowRouter.route(LIST_ROUTE_PATH, {
name: 'list',
action(params) {
Session.set('currentBoard', params.boardId);
Session.set('currentCard', null);
Session.set('popupCardId', null);
Session.set('popupCardBoardId', null);
Session.set('revealListId', params.listId);
Session.set('revealSwimlaneId', null);
Utils.manageCustomUI();
Utils.manageMatomo();
this.render('defaultLayout', {
content: 'board',
});
},
});
FlowRouter.route('/b/:boardId/:slug/:cardId', {
name: 'card',
action(params) {
Session.set('currentBoard', params.boardId);
Session.set('currentCard', params.cardId);
// A reveal is about the address you just followed, so following another
// one cancels it: without this, opening a card after a list link would
// scroll the board away from the card it just opened.
Session.set('revealSwimlaneId', null);
Session.set('revealListId', null);
Session.set('popupCardId', null);
Session.set('popupCardBoardId', null);
// #4758: if the card was moved to another board, redirect to its current one.
@@ -453,6 +508,8 @@ FlowRouter.route('/b/:id/:slug', {
const previousBoard = Session.get('currentBoard');
Session.set('currentBoard', currentBoard);
Session.set('currentCard', null);
Session.set('revealSwimlaneId', null);
Session.set('revealListId', null);
Session.set('popupCardId', null);
Session.set('popupCardBoardId', null);
+120
View File
@@ -0,0 +1,120 @@
# Design: linking to a swimlane, a list, or a card
Every one of the three has an address, and following it lands on the thing the
address names.
A card has had one since there has been a card route. A swimlane and a list had
none: "the Backlog list of this board" could only be sent as *open this board and
scroll down*. Worse, `List.absoluteUrl()` answered with the URL of whichever
**card** the cache returned first for that list — so the one place that did offer
a list link (`listMorePopup`) showed a card's address, and an empty box for an
empty list.
## The shape
```
/b/<boardId>/<slug>/<cardId> a card (unchanged)
/b/<boardId>/<slug>/swimlane/<swimlaneId> a swimlane
/b/<boardId>/<slug>/list/<listId> a list
```
**Five segments against the card route's four**, which is what keeps the three
apart: the card route cannot match a swimlane or list URL, and neither of those
can match a card. A guard checks all nine combinations, because losing a segment
would silently turn a link to a list into a link to a card called `list`.
The kind is a **word in the path** rather than a query parameter: it is part of
what the address names, and a reader can see which is which.
`models/lib/boardItemUrl.js` builds them and exports the route patterns, so
`config/router.js` registers the routes from the same constants the links are
built from — the two cannot disagree about the path when there is only one copy
of it.
It is pure and isomorphic, next to `models/lib/cardUrl.js` and for the same
reason: on the server `board()` is async and returns a Promise, so a caller there
passes the already-awaited board. A thenable is never read from — doing that is
what emitted `/b/undefined/board/...` in [#6427](https://github.com/wekan/wekan/issues/6427).
## Following the link reveals the thing
For a card that already worked: the route opens it. For a swimlane or a list
there is nothing to open, so the link has to **bring it into view**, or the
address named a place and took you to the top of the board instead.
**The route cannot do the scrolling.** It runs before the board has rendered, and
on a board that is already open it runs without re-creating anything — so at the
moment the address changes there is nothing on screen to scroll. The route
therefore *names* what to reveal in a Session value (`revealSwimlaneId`,
`revealListId`) and `client/lib/revealBoardItem.js`, started by the board body
once it has rendered, does the rest.
It **waits for the element** rather than assuming it. Swimlanes and lists arrive
as their subscriptions do and a large board renders in more than one pass, so a
single look on the next tick finds nothing on a cold load. It retries on a short
interval and **gives up after a few seconds**: a link to a list that was archived
or deleted names an element that is never going to exist, and the board is still
the right place to have landed.
The Session value is cleared as soon as it is acted on **or** given up on, so it
is a one-shot instruction about the address you followed rather than a standing
order that re-scrolls the board on every later render. It is cleared *before* the
scroll, because `scrollIntoView` can re-enter the autorun through the reactive
read and clearing first makes that second pass a no-op.
Every **other** board route clears it too. Without that, opening a card after a
list link would scroll the board away from the card it had just opened.
The element ids are the ones the templates already carry — `swimlane-<id>` and
`js-list-<id>` — held in `models/lib/revealBoardItem.js` as a **map**, not
derived by a rule. Deriving one name from another is how
`allBoardsMultiselectionSidebar` happened, and this failure is silent: nothing is
found and nothing is reported. A guard checks each id against the markup that
draws it.
The revealed element gets a brief outline. A scroll that lands mid-board gives no
sign of *which* of the things now on screen the link was about. It is an
`outline` rather than a border or shadow so it is drawn outside the box and moves
nothing by a pixel, and `prefers-reduced-motion` gets the outline without the
fade — the point is to say which one, and that does not need movement.
## Copying a link
All three are copied the same way, from the same kind of menu: the **first row**
of the hamburger popup — swimlane, list, and the card details menu — with the
link icon and the name `copy-link-to-clipboard` ("Copy link to clipboard")
beside it.
The card used to carry this as an **icon in its title header**, named only by a
tooltip, which is the one place a name cannot be read without hovering. That
button is gone, and so is its handler and the "Copied" tooltip only it used: a
handler for markup that no longer exists is dead code that reads as a working
feature.
**The copy row sits above every permission check.** Copying an address is
reading, not editing — somebody who may only read the board can still tell a
colleague which list they mean — while everything else in those menus changes the
board and stays guarded.
`absoluteUrl()`, not the relative path: what lands in the clipboard is pasted
into a chat or an email, and a relative path is only a link inside this page.
## Related files
| File Path | File Type | Description |
| --- | --- | --- |
| `models/lib/boardItemUrl.js` | `.js` module, pure | The URLs and the route patterns. No Meteor, so it is unit-testable and works on the server. |
| `models/lib/revealBoardItem.js` | `.js` module, pure | Which Session key each kind uses, and which element id to look for. |
| `client/lib/revealBoardItem.js` | `.js` client | Waits for the element, scrolls it into view, gives up rather than spinning. |
| `config/router.js` | `.js` routes | The two routes, and the clearing of a stale reveal on every other board route. |
| `models/lists.js`, `models/swimlanes.js` | `.js` collections | `originRelativeUrl` / `absoluteUrl` for each. |
| `client/components/swimlanes/swimlaneHeader.jade` | `.jade` template | The swimlane popup's copy row. |
| `client/components/lists/listHeader.jade` | `.jade` template | The list popup's copy row, and `listMorePopup`, whose link box now shows the list. |
| `client/components/cards/cardDetails.jade` | `.jade` template | The card menu's copy row — and the header button that is gone. |
| `client/components/swimlanes/swimlanes.css` | `.css` | The reveal outline. |
| `tests/boardItemLinks.test.cjs` | `.cjs` Node test | The URLs, that no address matches the wrong route, the reveal, the three copy rows, and the translations. |
## Related
- [The header](Header.md) — where the card's copy button used to be
- [Archive](Archive.md) — the other page a board menu row navigates to
+146
View File
@@ -0,0 +1,146 @@
# Design: the header
WeKan has **one** header bar. It is always on screen, it says where you are, and
it holds the controls of whatever page you are on.
There used to be two. The first was a thin strip with the house icon, the logo
and your account; the second was a coloured block that every page filled with its
own title and its own buttons. That second bar is gone from every page but the
few that still have something only it can hold, and `#header` is not rendered at
all where a page has none — it is a coloured block with a height of its own, so
leaving it in painted a tall empty strip under the first bar.
## What the bar says
Beside the house icon is **the page you are on**. It used to read "All Boards" on
every page, so the one bar that is always on screen named a place you were not.
`models/lib/pageTitles.js` maps a route name to a translation key. Three sources,
in order:
1. **the board's title**, wherever there is a board — the one thing worth having
there;
2. **a custom title** — Support and Accessibility can be renamed by an admin, and
Import names its source ("Import / Trello");
3. **the key** for everything else.
A board title and a custom title both come back as `title` rather than `key`,
because both are text to print as-is: neither may go through the translator, and
a board called "settings" is not the Admin Panel.
A route nobody has added answers with nothing and the bar shows nothing — better
than naming the wrong page.
### …and the path below it
Two pages are several places under one name, and for those the title continues
after a slash:
```
Admin Panel / Settings / Version
All Boards / Workspaces / Engineering / Backend
```
`headerTitleTrail()` in `client/components/main/header.js` returns **one list** of
segments rather than a helper per segment, because the two pages do not have the
same number of them — the Admin Panel always has two, and a workspace has as many
as its tree is deep. Each entry is one of the two forms a left-menu entry already
has: `key` for something translated, `title` for text that must not be.
The words are the ones the navigation beside it already uses — the Admin Panel's
tab key and its menu row's label ([Admin Panel URLs](Admin-Panel-URLs.md)), the
All Boards left-menu key and the workspace's own name
([All Boards URLs](All-Boards-URLs.md)) — so the title and the thing highlighted
next to it cannot say different things about one place.
It is read from the **URL** and from the user document, never from the pages
themselves. The header is a separate Blaze instance, and importing a page module
from it once ran that module before its own template was registered; the throw
aborted every module after it, which is why `client/lib/pageTitleSources.js`
exists — it registers no template and touches no DOM, so it is safe to load
early.
## What the bar holds
In source order: the house and the page title (plus the pencil that renames a
board), the logo, the phone/desktop toggle, the drag-handles toggle — and then
`.header-quick-access-end`, which holds everything else and is pushed to the end
of the bar by a single `margin-inline-start: auto`. That is a **logical**
property, so a right-to-left language mirrors it by itself rather than needing a
second rule kept in step with the first.
Inside that group: the starred-boards dropdown, the page's own controls, the
page's view menu, the Admin Panel's tabs, the notification bell, **a divider**,
help, your account, and the sidebar hamburger where the page has one.
The divider is the seam: everything before it belongs to the **page**, everything
after belongs to **you**. Without it the run of icons reads as one list of
unrelated things.
**Every button is an icon named by a tooltip.** The view menus lost their visible
labels — the board's said "Swimlanes", All Boards' said "Lists" — because the
label is the widest part of a button and the name is in the tooltip where the
other buttons of this bar already keep theirs. A tooltip is a poor place for a
name in general; it is the right one here only because the whole bar is icons and
consistent.
**The button of the page you are on keeps the hover background**, permanently and
a shade darker. Darker rather than equal: hovering the tab you are already on has
to still look like a hover.
### It wraps
`#header-quick-access` is `flex-wrap: wrap` with a row gap, and **every** height
on it is a minimum. It used to be one row with `overflow: hidden`, so a button
that did not fit was not drawn at all — and a button that is not drawn gives no
sign that it exists. Four phone rules pinned 40px or 48px; a fixed height cannot
hold two rows, so it would have cut off exactly what the wrap was for. A phone is
where the buttons run out of room first, which makes it the last place that
should hide them.
`--wekan-header-height` is what anything laid out against the viewport starts
below. It measures **both** bars — the bottom of the lowest one present, rather
than a sum of heights, so any margin between them counts and a bar that is absent
contributes nothing without a special case — and each bar has its own
`ResizeObserver`, because the first one wrapping to a second row is a resize of
that element and of nothing else. `client/lib/utils.js` keeps it current.
## The sidebar, and the hamburger
A page's controls used to live in its own second header bar beside its `h1`. The
title moved here and the controls moved into a **right sidebar**, so a page is its
content plus one panel rather than its content plus a strip of buttons.
`models/lib/pageSidebar.js` says which page gets what. A board has its own
sidebar and All Boards has its own; every other page with controls gets the
shared one, and a page with **no** controls gets no sidebar and no hamburger —
an empty panel is worse than none.
`NO_HAMBURGER_ROUTES` is the other half of it: a page can have a sidebar and
still not be offered a hamburger. All Boards is one — its four controls are in
this bar and Search and Multi-Selection open the sidebar straight into their own
view, so the hamburger's only destination was a menu listing what is already one
click away. A board is deliberately not in that list: what its sidebar holds —
members, labels, activities, settings — is not in the bar and has nowhere else to
be opened from.
## Related files
| File Path | File Type | Description |
| --- | --- | --- |
| `client/components/main/header.jade` | `.jade` template | The bar itself, and the starred-boards popup. |
| `client/components/main/header.js` | `.js` Blaze template logic | The title, the trail, which page gets what, and the hamburger's click. |
| `client/components/main/header.css` | `.css` | The wrap, the end group, the active mark, the divider. |
| `models/lib/pageTitles.js` | `.js` module, pure | Route name → title key, and the Admin Panel's second segment. |
| `models/lib/pageSidebar.js` | `.js` module, pure | Which sidebar a page has, and whether it is offered a hamburger. |
| `client/lib/pageTitleSources.js` | `.js` client | The three pages whose title is their own, without importing those pages. |
| `client/lib/utils.js` | `.js` client | `--wekan-header-height`, measured from both bars. |
| `tests/headerBars.test.cjs` | `.cjs` Node test | The wrap, the end group, the view menus, the active mark, the divider, and both title paths. |
| `tests/pageSidebar.test.cjs` | `.cjs` Node test | Which page has which sidebar, and where the hamburger is offered. |
## Related
- [Admin Panel URLs](Admin-Panel-URLs.md) — the panel's addresses and its title path
- [All Boards URLs](All-Boards-URLs.md) — the sections, workspaces and their title path
- [All Boards](All-Boards.md) — the four controls this bar holds there
- [Linking to a swimlane, list or card](Board-Item-Links.md) — where the card's copy button went
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Hapus Senarai semak?",
"checklistItemDeletePopup-title": "Hapus item senarai semak?",
"copy-card-link-to-clipboard": "Salin capaian kad ke papan klip",
"copy-link-to-clipboard": "Salin capaian ke papan klip",
"copy-text-to-clipboard": "Salin teks ke papan klip",
"linkCardPopup-title": "Paut Kad",
"searchElementPopup-title": "Cari",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Vee kontrolelys uit?",
"checklistItemDeletePopup-title": "Vee kontrolelysitem uit?",
"copy-card-link-to-clipboard": "Kopieer kaartskakel na knipbord",
"copy-link-to-clipboard": "Kopieer skakel na knipbord",
"copy-text-to-clipboard": "Kopieer teks na knipbord",
"linkCardPopup-title": "Koppelkaart",
"searchElementPopup-title": "Soek",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Vee kontrolelys uit?",
"checklistItemDeletePopup-title": "Vee kontrolelysitem uit?",
"copy-card-link-to-clipboard": "Kopieer kaartskakel na knipbord",
"copy-link-to-clipboard": "Kopieer skakel na knipbord",
"copy-text-to-clipboard": "Kopieer teks na knipbord",
"linkCardPopup-title": "Koppelkaart",
"searchElementPopup-title": "Soek",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Supprimer la check-list ?",
"checklistItemDeletePopup-title": "Supprimer l'élément de la check-list ?",
"copy-card-link-to-clipboard": "نسخ رابط البطاقة إلى الحافظة",
"copy-link-to-clipboard": "نسخ الرابط إلى الحافظة",
"copy-text-to-clipboard": "Copier le texte dans le presse-papier",
"linkCardPopup-title": "ربط البطاقة",
"searchElementPopup-title": "بحث",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "حذف قائمة التحقق؟",
"checklistItemDeletePopup-title": "حذف عنصر قائمة التحقق؟",
"copy-card-link-to-clipboard": "نسخ رابط البطاقة إلى الحافظة",
"copy-link-to-clipboard": "نسخ الرابط إلى الحافظة",
"copy-text-to-clipboard": "نسخ النص إلى الحافظة",
"linkCardPopup-title": "ربط البطاقة",
"searchElementPopup-title": "بحث",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "حذف قائمة التحقق؟",
"checklistItemDeletePopup-title": "حذف عنصر قائمة التحقق؟",
"copy-card-link-to-clipboard": "نسخ رابط البطاقة إلى الحافظة",
"copy-link-to-clipboard": "نسخ الرابط إلى الحافظة",
"copy-text-to-clipboard": "نسخ النص إلى الحافظة",
"linkCardPopup-title": "ربط البطاقة",
"searchElementPopup-title": "بحث",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "حذف قائمة التحقق؟",
"checklistItemDeletePopup-title": "حذف عنصر قائمة التحقق؟",
"copy-card-link-to-clipboard": "نسخ رابط البطاقة إلى الحافظة",
"copy-link-to-clipboard": "نسخ الرابط إلى الحافظة",
"copy-text-to-clipboard": "نسخ النص إلى الحافظة",
"linkCardPopup-title": "ربط البطاقة",
"searchElementPopup-title": "بحث",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "¿Borrar la lista de tareas?",
"checklistItemDeletePopup-title": "¿Eliminar l'elementu del checklist?",
"copy-card-link-to-clipboard": "Copiar el enlace de la tarjeta al portapapeles",
"copy-link-to-clipboard": "Copiar el enlace al portapapeles",
"copy-text-to-clipboard": "Copiar texto en el portapapeles",
"linkCardPopup-title": "Enlazar tarjeta",
"searchElementPopup-title": "Buscar",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Yoxlama siyahısı silinsin?",
"checklistItemDeletePopup-title": "Yoxlama siyahısı elementi silinsin?",
"copy-card-link-to-clipboard": "Kart linkini panoya kopyalayın",
"copy-link-to-clipboard": "Linki panoya kopyalayın",
"copy-text-to-clipboard": "Mətni panoya kopyalayın",
"linkCardPopup-title": "Əlaqə Kartı",
"searchElementPopup-title": "Axtar",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Yoxlama siyahısı silinsin?",
"checklistItemDeletePopup-title": "Yoxlama siyahısı elementi silinsin?",
"copy-card-link-to-clipboard": "Kart linkini panoya kopyalayın",
"copy-link-to-clipboard": "Linki panoya kopyalayın",
"copy-text-to-clipboard": "Mətni panoya kopyalayın",
"linkCardPopup-title": "Əlaqə Kartı",
"searchElementPopup-title": "Axtar",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Yoxlama siyahısı silinsin?",
"checklistItemDeletePopup-title": "Yoxlama siyahısı elementi silinsin?",
"copy-card-link-to-clipboard": "Kart linkini panoya kopyalayın",
"copy-link-to-clipboard": "Linki panoya kopyalayın",
"copy-text-to-clipboard": "Mətni panoya kopyalayın",
"linkCardPopup-title": "Əlaqə Kartı",
"searchElementPopup-title": "Axtar",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Выдаліць кантрольны спіс?",
"checklistItemDeletePopup-title": "Выдаліць пункт кантрольнага спіса?",
"copy-card-link-to-clipboard": "Скапіраваць спасылку на картку ў буфер абмену",
"copy-link-to-clipboard": "Скапіраваць спасылку ў буфер абмену",
"copy-text-to-clipboard": "Скапіраваць тэкст у буфер абмену",
"linkCardPopup-title": "Звязаць картку",
"searchElementPopup-title": "Пошук",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Избрисаћете предметну радњу?",
"checklistItemDeletePopup-title": "Избрисаћете ставку из предметне радње?",
"copy-card-link-to-clipboard": "Копирай връзката на картата в клипборда",
"copy-link-to-clipboard": "Копирай връзката в клипборда",
"copy-text-to-clipboard": "Причувај текст на кратко",
"linkCardPopup-title": "Свържи картата",
"searchElementPopup-title": "Търсене",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Supprimer la checklist ?",
"checklistItemDeletePopup-title": "Supprimer l'élément de la check-list ?",
"copy-card-link-to-clipboard": "Copier le lien de la carte dans le presse-papier",
"copy-link-to-clipboard": "Copy link to clipboard",
"copy-text-to-clipboard": "Copier le texte dans le presse-papier",
"linkCardPopup-title": "Lier une Carte",
"searchElementPopup-title": "Klask",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Vols suprimir la llista de comprovació?",
"checklistItemDeletePopup-title": "Voleu esborrar l'element de la checklist?",
"copy-card-link-to-clipboard": "Copia l'enllaç de la ftixa al porta-retalls",
"copy-link-to-clipboard": "Copia l'enllaç al porta-retalls",
"copy-text-to-clipboard": "Copia el text al porta-retalls",
"linkCardPopup-title": "Fitxa d'enllaç",
"searchElementPopup-title": "Cerca",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Vols suprimir la llista de comprovació?",
"checklistItemDeletePopup-title": "Voleu esborrar l'element de la checklist?",
"copy-card-link-to-clipboard": "Copia l'enllaç de la ftixa al porta-retalls",
"copy-link-to-clipboard": "Copia l'enllaç al porta-retalls",
"copy-text-to-clipboard": "Copia el text al porta-retalls",
"linkCardPopup-title": "Fitxa d'enllaç",
"searchElementPopup-title": "Cerca",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Vols suprimir la llista de comprovació?",
"checklistItemDeletePopup-title": "Voleu esborrar l'element de la checklist?",
"copy-card-link-to-clipboard": "Copia l'enllaç de la ftixa al porta-retalls",
"copy-link-to-clipboard": "Copia l'enllaç al porta-retalls",
"copy-text-to-clipboard": "Copia el text al porta-retalls",
"linkCardPopup-title": "Fitxa d'enllaç",
"searchElementPopup-title": "Cerca",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "删除清单?",
"checklistItemDeletePopup-title": "删除清单项目?",
"copy-card-link-to-clipboard": "将卡片链接复制到剪贴板",
"copy-link-to-clipboard": "复制链接到剪贴板",
"copy-text-to-clipboard": "将文本复制到剪贴板",
"linkCardPopup-title": "链接卡",
"searchElementPopup-title": "搜索",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Smazat checklist?",
"checklistItemDeletePopup-title": "Smazat položku checklistu?",
"copy-card-link-to-clipboard": "Kopírovat adresu karty do mezipaměti",
"copy-link-to-clipboard": "Kopírovat odkaz do schránky",
"copy-text-to-clipboard": "Kopírovat text do schránky",
"linkCardPopup-title": "Propojit kartu",
"searchElementPopup-title": "Hledat",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Smazat checklist?",
"checklistItemDeletePopup-title": "Smazat položku checklistu?",
"copy-card-link-to-clipboard": "Kopírovat adresu karty do mezipaměti",
"copy-link-to-clipboard": "Kopírovat odkaz do schránky",
"copy-text-to-clipboard": "Kopírovat text do schránky",
"linkCardPopup-title": "Propojit kartu",
"searchElementPopup-title": "Hledat",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Dileu Rhestr Wirio?",
"checklistItemDeletePopup-title": "Dileu Eitem Rhestr Wirio?",
"copy-card-link-to-clipboard": "Copïo dolen cerdyn i'r clipfwrdd",
"copy-link-to-clipboard": "Copïo dolen i'r clipfwrdd",
"copy-text-to-clipboard": "Copïo testun i'r clipfwrdd",
"linkCardPopup-title": "Cerdyn Cyswllt",
"searchElementPopup-title": "Chwiliwch",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Dileu Rhestr Wirio?",
"checklistItemDeletePopup-title": "Dileu Eitem Rhestr Wirio?",
"copy-card-link-to-clipboard": "Copïo dolen cerdyn i'r clipfwrdd",
"copy-link-to-clipboard": "Copïo dolen i'r clipfwrdd",
"copy-text-to-clipboard": "Copïo testun i'r clipfwrdd",
"linkCardPopup-title": "Cerdyn Cyswllt",
"searchElementPopup-title": "Chwiliwch",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Slet tjeklisten?",
"checklistItemDeletePopup-title": "Slet element på tjeklisten?",
"copy-card-link-to-clipboard": "Kopiér link til kort til udklipsholder",
"copy-link-to-clipboard": "Kopiér link til udklipsholder",
"copy-text-to-clipboard": "Kopier tekst til udklipsholder",
"linkCardPopup-title": "Sammenkæd kort",
"searchElementPopup-title": "Søg",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Checkliste löschen?",
"checklistItemDeletePopup-title": "Element der Checkliste löschen?",
"copy-card-link-to-clipboard": "Kopiere Link zur Karte in die Zwischenablage",
"copy-link-to-clipboard": "Link in die Zwischenablage kopieren",
"copy-text-to-clipboard": "Text in die Zwischenablage kopieren",
"linkCardPopup-title": "Karte verknüpfen",
"searchElementPopup-title": "Suche",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Checkliste löschen?",
"checklistItemDeletePopup-title": "Element der Checkliste löschen?",
"copy-card-link-to-clipboard": "Kopiere Link zur Karte in die Zwischenablage",
"copy-link-to-clipboard": "Link in die Zwischenablage kopieren",
"copy-text-to-clipboard": "Text in die Zwischenablage kopieren",
"linkCardPopup-title": "Karte verknüpfen",
"searchElementPopup-title": "Suche",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Checkliste löschen?",
"checklistItemDeletePopup-title": "Element der Checkliste löschen?",
"copy-card-link-to-clipboard": "Kopiere Link zur Karte in die Zwischenablage",
"copy-link-to-clipboard": "Link in die Zwischenablage kopieren",
"copy-text-to-clipboard": "Text in die Zwischenablage kopieren",
"linkCardPopup-title": "Karte verknüpfen",
"searchElementPopup-title": "Suche",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Checkliste löschen?",
"checklistItemDeletePopup-title": "Element der Checkliste löschen?",
"copy-card-link-to-clipboard": "Kopiere Link zur Karte in die Zwischenablage",
"copy-link-to-clipboard": "Link in die Zwischenablage kopieren",
"copy-text-to-clipboard": "Text in die Zwischenablage kopieren",
"linkCardPopup-title": "Karte verknüpfen",
"searchElementPopup-title": "Suche",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Eliminare checklist?",
"checklistItemDeletePopup-title": "Supprimer l'élément de la check-list ?",
"copy-card-link-to-clipboard": "Αντιγραφή του συνδέσμου της κάρτας στο clipboard",
"copy-link-to-clipboard": "Αντιγραφή του συνδέσμου στο clipboard",
"copy-text-to-clipboard": "Copia il testo negli appunti",
"linkCardPopup-title": "Σύνδεση Κάρτας",
"searchElementPopup-title": "Αναζήτηση",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Eliminare checklist?",
"checklistItemDeletePopup-title": "Supprimer l'élément de la check-list ?",
"copy-card-link-to-clipboard": "Αντιγραφή του συνδέσμου της κάρτας στο clipboard",
"copy-link-to-clipboard": "Αντιγραφή του συνδέσμου στο clipboard",
"copy-text-to-clipboard": "Copia il testo negli appunti",
"linkCardPopup-title": "Σύνδεση Κάρτας",
"searchElementPopup-title": "Αναζήτηση",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Delete Checklist?",
"checklistItemDeletePopup-title": "Delete Checklist Item?",
"copy-card-link-to-clipboard": "Copy card link to clipboard",
"copy-link-to-clipboard": "Copy link to clipboard",
"copy-text-to-clipboard": "Copy text to clipboard",
"linkCardPopup-title": "Link Card",
"searchElementPopup-title": "Search",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Delete Checklist?",
"checklistItemDeletePopup-title": "Delete Checklist Item?",
"copy-card-link-to-clipboard": "Copy card link to clipboard",
"copy-link-to-clipboard": "Copy link to clipboard",
"copy-text-to-clipboard": "Copy text to clipboard",
"linkCardPopup-title": "Link Card",
"searchElementPopup-title": "Search",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Delete Checklist?",
"checklistItemDeletePopup-title": "Delete Checklist Item?",
"copy-card-link-to-clipboard": "Copy card link to clipboard",
"copy-link-to-clipboard": "Copy link to clipboard",
"copy-text-to-clipboard": "Copy text to clipboard",
"linkCardPopup-title": "Link Card",
"searchElementPopup-title": "Search",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Delete Checklist?",
"checklistItemDeletePopup-title": "Delete Checklist Item?",
"copy-card-link-to-clipboard": "Copy card link to clipboard",
"copy-link-to-clipboard": "Copy link to clipboard",
"copy-text-to-clipboard": "Copy text to clipboard",
"linkCardPopup-title": "Link Card",
"searchElementPopup-title": "Search",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Delete Checklist?",
"checklistItemDeletePopup-title": "Delete Checklist Item?",
"copy-card-link-to-clipboard": "Copy card link to clipboard",
"copy-link-to-clipboard": "Copy link to clipboard",
"copy-text-to-clipboard": "Copy text to clipboard",
"linkCardPopup-title": "Link Card",
"searchElementPopup-title": "Search",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Delete Checklist?",
"checklistItemDeletePopup-title": "Delete Checklist Item?",
"copy-card-link-to-clipboard": "Copy card link to clipboard",
"copy-link-to-clipboard": "Copy link to clipboard",
"copy-text-to-clipboard": "Copy text to clipboard",
"linkCardPopup-title": "Link Card",
"searchElementPopup-title": "Search",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Delete Checklist?",
"checklistItemDeletePopup-title": "Delete Checklist Item?",
"copy-card-link-to-clipboard": "Copy card link to clipboard",
"copy-link-to-clipboard": "Copy link to clipboard",
"copy-text-to-clipboard": "Copy text to clipboard",
"linkCardPopup-title": "Link Card",
"searchElementPopup-title": "Search",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Delete Checklist?",
"checklistItemDeletePopup-title": "Delete Checklist Item?",
"copy-card-link-to-clipboard": "Copy card link to clipboard",
"copy-link-to-clipboard": "Copy link to clipboard",
"copy-text-to-clipboard": "Copy text to clipboard",
"linkCardPopup-title": "Link Card",
"searchElementPopup-title": "Search",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Delete Checklist?",
"checklistItemDeletePopup-title": "Delete Checklist Item?",
"copy-card-link-to-clipboard": "Copy card link to clipboard",
"copy-link-to-clipboard": "Copy link to clipboard",
"copy-text-to-clipboard": "Copy text to clipboard",
"linkCardPopup-title": "Link Card",
"searchElementPopup-title": "Search",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Delete Checklist?",
"checklistItemDeletePopup-title": "Delete Checklist Item?",
"copy-card-link-to-clipboard": "Copy card link to clipboard",
"copy-link-to-clipboard": "Copy link to clipboard",
"copy-text-to-clipboard": "Copy text to clipboard",
"linkCardPopup-title": "Link Card",
"searchElementPopup-title": "Search",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Delete Checklist?",
"checklistItemDeletePopup-title": "Delete Checklist Item?",
"copy-card-link-to-clipboard": "Copy card link to clipboard",
"copy-link-to-clipboard": "Copy link to clipboard",
"copy-text-to-clipboard": "Copy text to clipboard",
"linkCardPopup-title": "Link Card",
"searchElementPopup-title": "Search",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Delete Checklist?",
"checklistItemDeletePopup-title": "Delete Checklist Item?",
"copy-card-link-to-clipboard": "Copy card link to clipboard",
"copy-link-to-clipboard": "Copy link to clipboard",
"copy-text-to-clipboard": "Copy text to clipboard",
"linkCardPopup-title": "Link Card",
"searchElementPopup-title": "Search",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "¿Borrar la lista de tareas?",
"checklistItemDeletePopup-title": "Supprimer l'élément de la check-list ?",
"copy-card-link-to-clipboard": "Copiar el enlace de la tarjeta al portapapeles",
"copy-link-to-clipboard": "Copy link to clipboard",
"copy-text-to-clipboard": "Copiar texto en el portapapeles",
"linkCardPopup-title": "Enlazar tarjeta",
"searchElementPopup-title": "Serĉi",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "¿Borrar la lista de tareas?",
"checklistItemDeletePopup-title": "¿Eliminar elemento de la checklist?",
"copy-card-link-to-clipboard": "Copiar enlace a tarjeta en el portapapeles",
"copy-link-to-clipboard": "Copiar el enlace al portapapeles",
"copy-text-to-clipboard": "Copiar texto en el portapapeles",
"linkCardPopup-title": "Tarjeta vinculada",
"searchElementPopup-title": "Buscar",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "¿Borrar la lista de tareas?",
"checklistItemDeletePopup-title": "¿Eliminar elemento de la checklist?",
"copy-card-link-to-clipboard": "Copiar el enlace de la tarjeta al portapapeles",
"copy-link-to-clipboard": "Copiar el enlace al portapapeles",
"copy-text-to-clipboard": "Copiar texto en el portapapeles",
"linkCardPopup-title": "Enlazar tarjeta",
"searchElementPopup-title": "Buscar",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "¿Borrar la lista de tareas?",
"checklistItemDeletePopup-title": "¿Eliminar elemento de la checklist?",
"copy-card-link-to-clipboard": "Copiar el enlace de la tarjeta al portapapeles",
"copy-link-to-clipboard": "Copiar el enlace al portapapeles",
"copy-text-to-clipboard": "Copiar texto en el portapapeles",
"linkCardPopup-title": "Enlazar tarjeta",
"searchElementPopup-title": "Buscar",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "¿Borrar la lista de tareas?",
"checklistItemDeletePopup-title": "¿Eliminar elemento de la checklist?",
"copy-card-link-to-clipboard": "Copiar el enlace de la tarjeta al portapapeles",
"copy-link-to-clipboard": "Copiar el enlace al portapapeles",
"copy-text-to-clipboard": "Copiar texto en el portapapeles",
"linkCardPopup-title": "Enlazar tarjeta",
"searchElementPopup-title": "Buscar",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "¿Borrar la lista de tareas?",
"checklistItemDeletePopup-title": "¿Eliminar elemento de la checklist?",
"copy-card-link-to-clipboard": "Copiar el enlace de la tarjeta al portapapeles",
"copy-link-to-clipboard": "Copiar el enlace al portapapeles",
"copy-text-to-clipboard": "Copiar texto en el portapapeles",
"linkCardPopup-title": "Enlazar tarjeta",
"searchElementPopup-title": "Buscar",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "¿Borrar la lista de tareas?",
"checklistItemDeletePopup-title": "¿Eliminar elemento de la checklist?",
"copy-card-link-to-clipboard": "Copiar el enlace de la tarjeta al portapapeles",
"copy-link-to-clipboard": "Copiar el enlace al portapapeles",
"copy-text-to-clipboard": "Copiar texto en el portapapeles",
"linkCardPopup-title": "Enlazar tarjeta",
"searchElementPopup-title": "Buscar",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "¿Borrar la lista de tareas?",
"checklistItemDeletePopup-title": "¿Eliminar elemento de la checklist?",
"copy-card-link-to-clipboard": "Copiar el enlace de la tarjeta al portapapeles",
"copy-link-to-clipboard": "Copiar el enlace al portapapeles",
"copy-text-to-clipboard": "Copiar texto en el portapapeles",
"linkCardPopup-title": "Enlazar tarjeta",
"searchElementPopup-title": "Buscar",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "¿Borrar la lista de tareas?",
"checklistItemDeletePopup-title": "¿Eliminar elemento de la checklist?",
"copy-card-link-to-clipboard": "Copiar el enlace de la tarjeta al portapapeles",
"copy-link-to-clipboard": "Copiar el enlace al portapapeles",
"copy-text-to-clipboard": "Copiar texto en el portapapeles",
"linkCardPopup-title": "Enlazar tarjeta",
"searchElementPopup-title": "Buscar",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Kustuta kontrollnimekiri?",
"checklistItemDeletePopup-title": "Kustutada kontrollnimekirja objekt?",
"copy-card-link-to-clipboard": "Kopeeri kaardi link lõikelauale",
"copy-link-to-clipboard": "Kopeeri link lõikelauale",
"copy-text-to-clipboard": "Teksti kopeerimine lõikelauale",
"linkCardPopup-title": "Linkkaart",
"searchElementPopup-title": "Otsi",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Ezabatu kontrol-zerrenda?",
"checklistItemDeletePopup-title": "Kontrol-zerrendako elementua ezabatu?",
"copy-card-link-to-clipboard": "Kopiatu txartela arbelera",
"copy-link-to-clipboard": "Kopiatu esteka arbelean",
"copy-text-to-clipboard": "Kopiatu testua arbelean",
"linkCardPopup-title": "Estekatu txartela",
"searchElementPopup-title": "Bilatu",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "چک‌لیست حذف شود؟",
"checklistItemDeletePopup-title": "آیتم چک‌لیست حذف شود؟",
"copy-card-link-to-clipboard": "درج پیوند کارت در حافظه",
"copy-link-to-clipboard": "کپی پیوند در کلیپ‌بورد",
"copy-text-to-clipboard": "کپی متن در کلیپ‌بورد",
"linkCardPopup-title": "ارتباط دادن کارت",
"searchElementPopup-title": "جستجو",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "چک‌لیست حذف شود؟",
"checklistItemDeletePopup-title": "آیتم چک‌لیست حذف شود؟",
"copy-card-link-to-clipboard": "درج پیوند کارت در حافظه",
"copy-link-to-clipboard": "کپی پیوند در کلیپ‌بورد",
"copy-text-to-clipboard": "کپی متن در کلیپ‌بورد",
"linkCardPopup-title": "ارتباط دادن کارت",
"searchElementPopup-title": "جستجو",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Poista tarkistuslista?",
"checklistItemDeletePopup-title": "Poista tarkistuslistan kohta?",
"copy-card-link-to-clipboard": "Kopioi kortin linkki leikepöydälle",
"copy-link-to-clipboard": "Kopioi linkki leikepöydälle",
"copy-text-to-clipboard": "Kopioi teksti leikepöydälle",
"linkCardPopup-title": "Linkitä kortti",
"searchElementPopup-title": "Etsi",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Supprimer la check-list ?",
"checklistItemDeletePopup-title": "Supprimer l'élément de la check-list ?",
"copy-card-link-to-clipboard": "Copier le lien de la carte dans le presse-papier",
"copy-link-to-clipboard": "Copier le lien dans le presse-papier",
"copy-text-to-clipboard": "Copier le texte dans le presse-papier",
"linkCardPopup-title": "Lier une Carte",
"searchElementPopup-title": "Chercher",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Supprimer la checklist ?",
"checklistItemDeletePopup-title": "Supprimer l'élément de la check-list ?",
"copy-card-link-to-clipboard": "Copier le lien de la carte dans le presse-papier",
"copy-link-to-clipboard": "Copier le lien dans le presse-papier",
"copy-text-to-clipboard": "Copier le texte dans le presse-papier",
"linkCardPopup-title": "Lier une Carte",
"searchElementPopup-title": "Chercher",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Supprimer la check-list ?",
"checklistItemDeletePopup-title": "Supprimer l'élément de la check-list ?",
"copy-card-link-to-clipboard": "Copier le lien de la carte dans le presse-papier",
"copy-link-to-clipboard": "Copier le lien dans le presse-papier",
"copy-text-to-clipboard": "Copier le texte dans le presse-papier",
"linkCardPopup-title": "Lier une Carte",
"searchElementPopup-title": "Chercher",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Kontrolearje wiskje?",
"checklistItemDeletePopup-title": "Checklist-item wiskje?",
"copy-card-link-to-clipboard": "Kopiearje kaartkeppeling nei klamboerd",
"copy-link-to-clipboard": "Kopiearje keppeling nei klamboerd",
"copy-text-to-clipboard": "Kopiearje tekst nei klamboerd",
"linkCardPopup-title": "Kaart keppelje",
"searchElementPopup-title": "Sykje",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Kontrolearje wiskje?",
"checklistItemDeletePopup-title": "Checklist-item wiskje?",
"copy-card-link-to-clipboard": "Kopiearje kaartkeppeling nei klamboerd",
"copy-link-to-clipboard": "Kopiearje keppeling nei klamboerd",
"copy-text-to-clipboard": "Kopiearje tekst nei klamboerd",
"linkCardPopup-title": "Kaart keppelje",
"searchElementPopup-title": "Sykje",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Eliminar lista de verificação?",
"checklistItemDeletePopup-title": "Excluir Item da Lista de Verificação?",
"copy-card-link-to-clipboard": "Copiar a ligação do cartão para a área de transferência",
"copy-link-to-clipboard": "Copiar a ligazón ao portapapeis",
"copy-text-to-clipboard": "Copiar texto para a área de transferência",
"linkCardPopup-title": "Ligar Cartão",
"searchElementPopup-title": "Procurar",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Eliminar lista de verificação?",
"checklistItemDeletePopup-title": "Excluir Item da Lista de Verificação?",
"copy-card-link-to-clipboard": "Copiar a ligação do cartão para a área de transferência",
"copy-link-to-clipboard": "Copiar a ligazón ao portapapeis",
"copy-text-to-clipboard": "Copiar texto para a área de transferência",
"linkCardPopup-title": "Ligar Cartão",
"searchElementPopup-title": "Procurar",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "ચેકલિસ્ટ ડિલીટ કરીએ?",
"checklistItemDeletePopup-title": "ચેકલિસ્ટ આઇટમ કાઢી નાખીએ?",
"copy-card-link-to-clipboard": "ક્લિપબોર્ડ પર કાર્ડ લિંક કૉપિ કરો",
"copy-link-to-clipboard": "ક્લિપબોર્ડ પર લિંક કૉપિ કરો",
"copy-text-to-clipboard": "ટેક્સ્ટને ક્લિપબોર્ડ પર કૉપિ કરો",
"linkCardPopup-title": "લિંક કાર્ડ",
"searchElementPopup-title": "શોધો",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "למחוק רשימת מטלות?",
"checklistItemDeletePopup-title": "למחוק פריט רשימת סימון?",
"copy-card-link-to-clipboard": "העתקת קישור הכרטיס ללוח הגזירים",
"copy-link-to-clipboard": "העתקת קישור ללוח הגזירים",
"copy-text-to-clipboard": "העתקת טקסט ללוח הגזירים",
"linkCardPopup-title": "קישור כרטיס",
"searchElementPopup-title": "חיפוש",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "למחוק רשימת מטלות?",
"checklistItemDeletePopup-title": "למחוק פריט רשימת סימון?",
"copy-card-link-to-clipboard": "העתקת קישור הכרטיס ללוח הגזירים",
"copy-link-to-clipboard": "העתקת קישור ללוח הגזירים",
"copy-text-to-clipboard": "העתקת טקסט ללוח הגזירים",
"linkCardPopup-title": "קישור כרטיס",
"searchElementPopup-title": "חיפוש",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "ચેકલિસ્ટ ડિલીટ કરીએ?",
"checklistItemDeletePopup-title": "ચેકલિસ્ટ આઇટમ કાઢી નાખીએ?",
"copy-card-link-to-clipboard": "कॉपी कार्ड क्लिपबोर्ड करने के लिए लिंक",
"copy-link-to-clipboard": "Copy link to clipboard",
"copy-text-to-clipboard": "ટેક્સ્ટને ક્લિપબોર્ડ પર કૉપિ કરો",
"linkCardPopup-title": "कार्ड कड़ी",
"searchElementPopup-title": "શોધો",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "ચેકલિસ્ટ ડિલીટ કરીએ?",
"checklistItemDeletePopup-title": "ચેકલિસ્ટ આઇટમ કાઢી નાખીએ?",
"copy-card-link-to-clipboard": "कॉपी कार्ड क्लिपबोर्ड करने के लिए लिंक",
"copy-link-to-clipboard": "Copy link to clipboard",
"copy-text-to-clipboard": "ટેક્સ્ટને ક્લિપબોર્ડ પર કૉપિ કરો",
"linkCardPopup-title": "कार्ड कड़ी",
"searchElementPopup-title": "શોધો",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Избрисаћете предметну радњу?",
"checklistItemDeletePopup-title": "Избрисаћете ставку из предметне радње?",
"copy-card-link-to-clipboard": "Причувај везу на кратко",
"copy-link-to-clipboard": "Copy link to clipboard",
"copy-text-to-clipboard": "Причувај текст на кратко",
"linkCardPopup-title": "Повежи предмет",
"searchElementPopup-title": "Traži",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Törlöd az ellenőrzőlistát?",
"checklistItemDeletePopup-title": "Törlöd az ellenőrzőlista-elemet?",
"copy-card-link-to-clipboard": "Kártya hivatkozásának másolása a vágólapra",
"copy-link-to-clipboard": "Hivatkozás másolása a vágólapra",
"copy-text-to-clipboard": "Szöveg másolása vágólapra",
"linkCardPopup-title": "Kártyára hivatkozás",
"searchElementPopup-title": "Keresés",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Ջնջե՞լ ստուգաթերթը:",
"checklistItemDeletePopup-title": "Ջնջե՞լ ստուգաթերթի կետը:",
"copy-card-link-to-clipboard": "Պատճենել քարտի հղումը սեղմատախտակին",
"copy-link-to-clipboard": "Պատճենել հղումը սեղմատախտակին",
"copy-text-to-clipboard": "Պատճենել տեքստը clipboard-ում",
"linkCardPopup-title": "Հղման քարտ",
"searchElementPopup-title": "Որոնում",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Hapus Senarai semak?",
"checklistItemDeletePopup-title": "Hapus item senarai semak?",
"copy-card-link-to-clipboard": "Salin capaian kad ke papan klip",
"copy-link-to-clipboard": "Salin capaian ke papan klip",
"copy-text-to-clipboard": "Salin teks ke papan klip",
"linkCardPopup-title": "Paut Kad",
"searchElementPopup-title": "Cari",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Hichapụ ndepụta nlele?",
"checklistItemDeletePopup-title": "Hichapụ ihe ndetu ihe?",
"copy-card-link-to-clipboard": "Detuo njikọ kaadị na klipbọọdụ",
"copy-link-to-clipboard": "Detuo njikọ na klipbọọdụ",
"copy-text-to-clipboard": "Detuo ederede na klipbọọdụ",
"linkCardPopup-title": "Kaadị njikọ",
"searchElementPopup-title": "Chọọ",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Eliminare checklist?",
"checklistItemDeletePopup-title": "Eliminare l'elemento della checklist?",
"copy-card-link-to-clipboard": "Copia link della scheda negli appunti",
"copy-link-to-clipboard": "Copia il link negli appunti",
"copy-text-to-clipboard": "Copia il testo negli appunti",
"linkCardPopup-title": "Collega scheda",
"searchElementPopup-title": "Cerca",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "チェックリストを削除しますか?",
"checklistItemDeletePopup-title": "チェックリスト項目を削除しますか?",
"copy-card-link-to-clipboard": "カードへのリンクをクリップボードにコピー",
"copy-link-to-clipboard": "リンクをクリップボードにコピー",
"copy-text-to-clipboard": "テキストをクリップボードにコピー",
"linkCardPopup-title": "カードをリンク",
"searchElementPopup-title": "検索",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "チェックリストを削除しますか?",
"checklistItemDeletePopup-title": "チェックリスト項目を削除しますか?",
"copy-card-link-to-clipboard": "カードへのリンクをクリップボードにコピー",
"copy-link-to-clipboard": "リンクをクリップボードにコピー",
"copy-text-to-clipboard": "テキストをクリップボードにコピー",
"linkCardPopup-title": "カードをリンク",
"searchElementPopup-title": "検索",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Удалить Чек-лист?",
"checklistItemDeletePopup-title": "წაიშალოს საკონტროლო სიის ელემენტი?",
"copy-card-link-to-clipboard": "დააკოპირეთ ბარათის ბმული clipboard-ზე",
"copy-link-to-clipboard": "დააკოპირეთ ბმული clipboard-ზე",
"copy-text-to-clipboard": "Скопировать текст в буфер обмена",
"linkCardPopup-title": "Карточка-ссылка",
"searchElementPopup-title": "ძებნა",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "លុបបញ្ជីត្រួតពិនិត្យ?",
"checklistItemDeletePopup-title": "លុបធាតុបញ្ជីត្រួតពិនិត្យ?",
"copy-card-link-to-clipboard": "ចម្លងតំណកាតទៅក្ដារតម្បៀតខ្ទាស់",
"copy-link-to-clipboard": "ចម្លងតំណទៅក្ដារតម្បៀតខ្ទាស់",
"copy-text-to-clipboard": "ចម្លងអត្ថបទទៅក្ដារតម្បៀតខ្ទាស់",
"linkCardPopup-title": "កាតភ្ជាប់",
"searchElementPopup-title": "ស្វែងរក",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "លុបបញ្ជីត្រួតពិនិត្យ?",
"checklistItemDeletePopup-title": "លុបធាតុបញ្ជីត្រួតពិនិត្យ?",
"copy-card-link-to-clipboard": "ចម្លងតំណកាតទៅក្ដារតម្បៀតខ្ទាស់",
"copy-link-to-clipboard": "ចម្លងតំណទៅក្ដារតម្បៀតខ្ទាស់",
"copy-text-to-clipboard": "ចម្លងអត្ថបទទៅក្ដារតម្បៀតខ្ទាស់",
"linkCardPopup-title": "កាតភ្ជាប់",
"searchElementPopup-title": "ស្វែងរក",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "체크리스트를 삭제합니까?",
"checklistItemDeletePopup-title": "チェックリスト項目を削除しますか?",
"copy-card-link-to-clipboard": "클립보드에 카드의 링크가 복사되었습니다.",
"copy-link-to-clipboard": "링크를 클립보드에 복사합니다",
"copy-text-to-clipboard": "텍스트를 클립보드에 복사합니다",
"linkCardPopup-title": "카드 연결",
"searchElementPopup-title": "검색",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "체크리스트를 삭제합니까?",
"checklistItemDeletePopup-title": "チェックリスト項目を削除しますか?",
"copy-card-link-to-clipboard": "클립보드에 카드의 링크가 복사되었습니다.",
"copy-link-to-clipboard": "링크를 클립보드에 복사합니다",
"copy-text-to-clipboard": "텍스트를 클립보드에 복사합니다",
"linkCardPopup-title": "카드 연결",
"searchElementPopup-title": "검색",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Ištrinti kontrolinį sąrašą?",
"checklistItemDeletePopup-title": "Ištrinti kontrolinio sąrašo elementą?",
"copy-card-link-to-clipboard": "Nukopijuokite kortelės nuorodą į mainų sritį",
"copy-link-to-clipboard": "Nukopijuokite nuorodą į mainų sritį",
"copy-text-to-clipboard": "Nukopijuokite tekstą į mainų sritį",
"linkCardPopup-title": "Nuorodų kortelė",
"searchElementPopup-title": "Ieškoti",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Ištrinti kontrolinį sąrašą?",
"checklistItemDeletePopup-title": "Ištrinti kontrolinio sąrašo elementą?",
"copy-card-link-to-clipboard": "Kopet kartiņas saiti starpliktuvē",
"copy-link-to-clipboard": "Kopēt saiti starpliktuvē",
"copy-text-to-clipboard": "Nukopijuokite tekstą į mainų sritį",
"linkCardPopup-title": "Kartiņas saite",
"searchElementPopup-title": "Meklēt",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Избрисаћете предметну радњу?",
"checklistItemDeletePopup-title": "Избрисаћете ставку из предметне радње?",
"copy-card-link-to-clipboard": "Копирай връзката на картата в клипборда",
"copy-link-to-clipboard": "Copy link to clipboard",
"copy-text-to-clipboard": "Причувај текст на кратко",
"linkCardPopup-title": "Поврзи картичка",
"searchElementPopup-title": "Барај",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Удалить Чек-лист?",
"checklistItemDeletePopup-title": "Чеклистийн зүйлийг устгах уу?",
"copy-card-link-to-clipboard": "Копировать ссылку на карточку в буфер обмена",
"copy-link-to-clipboard": "Копировать ссылку в буфер обмена",
"copy-text-to-clipboard": "Скопировать текст в буфер обмена",
"linkCardPopup-title": "Карточка-ссылка",
"searchElementPopup-title": "Поиск",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Hapus Senarai semak?",
"checklistItemDeletePopup-title": "Hapus item senarai semak?",
"copy-card-link-to-clipboard": "Salin capaian kad ke papan klip",
"copy-link-to-clipboard": "Salin capaian ke papan klip",
"copy-text-to-clipboard": "Salin teks ke papan klip",
"linkCardPopup-title": "Paut Kad",
"searchElementPopup-title": "Cari",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Hapus Senarai semak?",
"checklistItemDeletePopup-title": "Hapus item senarai semak?",
"copy-card-link-to-clipboard": "Salin capaian kad ke papan klip",
"copy-link-to-clipboard": "Salin capaian ke papan klip",
"copy-text-to-clipboard": "Salin teks ke papan klip",
"linkCardPopup-title": "Paut Kad",
"searchElementPopup-title": "Cari",
+1
View File
@@ -465,6 +465,7 @@
"checklistDeletePopup-title": "Slette sjekklisten?",
"checklistItemDeletePopup-title": "Slette sjekklisteelement?",
"copy-card-link-to-clipboard": "Kopier lenke",
"copy-link-to-clipboard": "Kopier lenke til utklippstavlen",
"copy-text-to-clipboard": "Kopier tekst til utklippstavlen",
"linkCardPopup-title": "Link Kort",
"searchElementPopup-title": "Søk",
Loaded 100 of 165 files, more files were not shown because too many files have changed in this diff. Show more