mirror of
https://github.com/kremalicious/umami.git
synced 2025-02-14 21:10:34 +01:00
commit
2f24a8775e
@ -12,15 +12,11 @@ WORKDIR /app
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
COPY . .
|
||||
|
||||
ARG DATABASE_URL
|
||||
ARG DATABASE_TYPE
|
||||
ARG BASE_PATH
|
||||
ARG DISABLE_LOGIN
|
||||
|
||||
ENV DATABASE_URL $DATABASE_URL
|
||||
ENV DATABASE_TYPE $DATABASE_TYPE
|
||||
ENV BASE_PATH $BASE_PATH
|
||||
ENV DISABLE_LOGIN $DISABLE_LOGIN
|
||||
|
||||
ENV NEXT_TELEMETRY_DISABLED 1
|
||||
|
||||
@ -36,12 +32,11 @@ ENV NEXT_TELEMETRY_DISABLED 1
|
||||
RUN addgroup --system --gid 1001 nodejs
|
||||
RUN adduser --system --uid 1001 nextjs
|
||||
|
||||
RUN yarn global add prisma
|
||||
RUN yarn add npm-run-all dotenv
|
||||
RUN yarn add npm-run-all dotenv prisma
|
||||
|
||||
# You only need to copy next.config.js if you are NOT using the default configuration
|
||||
COPY --from=builder /app/next.config.js .
|
||||
COPY --from=builder /app/public ./public
|
||||
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
|
||||
COPY --from=builder /app/package.json ./package.json
|
||||
COPY --from=builder /app/prisma ./prisma
|
||||
COPY --from=builder /app/scripts ./scripts
|
||||
|
@ -30,7 +30,7 @@ export default function UpdateNotice() {
|
||||
if (!checked) {
|
||||
checkVersion();
|
||||
}
|
||||
}, []);
|
||||
}, [checked]);
|
||||
|
||||
if (!hasUpdate || dismissed) {
|
||||
return null;
|
||||
|
@ -4,10 +4,12 @@ import { useRouter } from 'next/router';
|
||||
import Button from 'components/common/Button';
|
||||
import FormLayout, { FormButtons, FormRow } from 'components/layout/FormLayout';
|
||||
import CopyButton from 'components/common/CopyButton';
|
||||
import useConfig from 'hooks/useConfig';
|
||||
|
||||
export default function TrackingCodeForm({ values, onClose }) {
|
||||
const ref = useRef();
|
||||
const { basePath } = useRouter();
|
||||
const { trackerScriptName } = useConfig();
|
||||
|
||||
return (
|
||||
<FormLayout>
|
||||
@ -24,7 +26,9 @@ export default function TrackingCodeForm({ values, onClose }) {
|
||||
rows={3}
|
||||
cols={60}
|
||||
spellCheck={false}
|
||||
defaultValue={`<script async defer data-website-id="${values.website_uuid}" src="${document.location.origin}${basePath}/umami.js"></script>`}
|
||||
defaultValue={`<script async defer data-website-id="${values.website_uuid}" src="${
|
||||
document.location.origin
|
||||
}${basePath}/${trackerScriptName ? `${trackerScriptName}.js` : 'umami.js'}"></script>`}
|
||||
readOnly
|
||||
/>
|
||||
</FormRow>
|
||||
|
@ -1,13 +1,13 @@
|
||||
import React from 'react';
|
||||
import { useRouter } from 'next/router';
|
||||
import Script from 'next/script';
|
||||
import classNames from 'classnames';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import Link from 'components/common/Link';
|
||||
import styles from './Footer.module.css';
|
||||
import useStore from 'store/version';
|
||||
import { HOMEPAGE_URL, REPO_URL } from 'lib/constants';
|
||||
import { CURRENT_VERSION, HOMEPAGE_URL, REPO_URL } from 'lib/constants';
|
||||
|
||||
export default function Footer() {
|
||||
const { current } = useStore();
|
||||
const { pathname } = useRouter();
|
||||
|
||||
return (
|
||||
<footer className={classNames(styles.footer, 'row')}>
|
||||
@ -26,11 +26,9 @@ export default function Footer() {
|
||||
/>
|
||||
</div>
|
||||
<div className={classNames(styles.version, 'col-12 col-md-4')}>
|
||||
<Link href={REPO_URL}>{`v${current}`}</Link>
|
||||
<Link href={REPO_URL}>{`v${CURRENT_VERSION}`}</Link>
|
||||
</div>
|
||||
{!process.env.telemetryDisabled && (
|
||||
<img src={`https://i.umami.is/a.png?v=${current}`} alt="" />
|
||||
)}
|
||||
{!pathname.includes('/share/') && <Script src={`/telemetry.js`} />}
|
||||
</footer>
|
||||
);
|
||||
}
|
||||
|
@ -8,22 +8,26 @@ import ThemeButton from 'components/settings/ThemeButton';
|
||||
import HamburgerButton from 'components/common/HamburgerButton';
|
||||
import UpdateNotice from 'components/common/UpdateNotice';
|
||||
import UserButton from 'components/settings/UserButton';
|
||||
import { HOMEPAGE_URL } from 'lib/constants';
|
||||
import useConfig from '/hooks/useConfig';
|
||||
import useUser from 'hooks/useUser';
|
||||
import Logo from 'assets/logo.svg';
|
||||
import styles from './Header.module.css';
|
||||
import useUser from 'hooks/useUser';
|
||||
import { HOMEPAGE_URL } from 'lib/constants';
|
||||
|
||||
export default function Header() {
|
||||
const { user } = useUser();
|
||||
const { pathname } = useRouter();
|
||||
const { updatesDisabled } = useConfig();
|
||||
const isSharePage = pathname.includes('/share/');
|
||||
const allowUpdate = user?.is_admin && !updatesDisabled && !isSharePage;
|
||||
|
||||
return (
|
||||
<>
|
||||
{user?.is_admin && !process.env.updatesDisabled && <UpdateNotice />}
|
||||
{allowUpdate && <UpdateNotice />}
|
||||
<header className={classNames(styles.header, 'row')}>
|
||||
<div className={styles.title}>
|
||||
<Icon icon={<Logo />} size="large" className={styles.logo} />
|
||||
<Link href={pathname.includes('/share') ? HOMEPAGE_URL : '/'}>umami</Link>
|
||||
<Link href={isSharePage ? HOMEPAGE_URL : '/'}>umami</Link>
|
||||
</div>
|
||||
<HamburgerButton />
|
||||
{user && (
|
||||
|
@ -12,7 +12,7 @@ export default function EventsChart({ websiteId, className, token }) {
|
||||
const [{ startDate, endDate, unit, modified }] = useDateRange(websiteId);
|
||||
const [timezone] = useTimezone();
|
||||
const {
|
||||
query: { url, eventType },
|
||||
query: { url, eventName },
|
||||
} = usePageQuery();
|
||||
|
||||
const { data, loading } = useFetch(
|
||||
@ -24,11 +24,11 @@ export default function EventsChart({ websiteId, className, token }) {
|
||||
unit,
|
||||
tz: timezone,
|
||||
url,
|
||||
event_type: eventType,
|
||||
event_name: eventName,
|
||||
token,
|
||||
},
|
||||
},
|
||||
[modified, eventType],
|
||||
[modified, eventName],
|
||||
);
|
||||
|
||||
const datasets = useMemo(() => {
|
||||
|
@ -1,62 +1,26 @@
|
||||
import React, { useState } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
import MetricsTable from './MetricsTable';
|
||||
import Tag from 'components/common/Tag';
|
||||
import DropDown from 'components/common/DropDown';
|
||||
import { eventTypeFilter } from 'lib/filters';
|
||||
import usePageQuery from 'hooks/usePageQuery';
|
||||
import styles from './EventsTable.module.css';
|
||||
|
||||
const EVENT_FILTER_DEFAULT = {
|
||||
value: 'all',
|
||||
label: <FormattedMessage id="label.all-events" defaultMessage="All events" />,
|
||||
};
|
||||
const messages = defineMessages({
|
||||
events: { id: 'metrics.events', defaultMessage: 'Events' },
|
||||
actions: { id: 'metrics.actions', defaultMessage: 'Actions' },
|
||||
});
|
||||
|
||||
export default function EventsTable({ websiteId, ...props }) {
|
||||
const [eventType, setEventType] = useState(EVENT_FILTER_DEFAULT.value);
|
||||
const [eventTypes, setEventTypes] = useState([]);
|
||||
const { resolve, router } = usePageQuery();
|
||||
|
||||
const dropDownOptions = [EVENT_FILTER_DEFAULT, ...eventTypes.map(t => ({ value: t, label: t }))];
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
function handleDataLoad(data) {
|
||||
setEventTypes([...new Set(data.map(({ x }) => x.split('\t')[0]))]);
|
||||
props.onDataLoad?.(data);
|
||||
}
|
||||
|
||||
function handleChange(value) {
|
||||
router.replace(resolve({ eventType: value === 'all' ? undefined : value }));
|
||||
setEventType(value);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{eventTypes?.length > 1 && (
|
||||
<div className={styles.filter}>
|
||||
<DropDown value={eventType} options={dropDownOptions} onChange={handleChange} />
|
||||
</div>
|
||||
)}
|
||||
<MetricsTable
|
||||
{...props}
|
||||
title={<FormattedMessage id="metrics.events" defaultMessage="Events" />}
|
||||
title={formatMessage(messages.events)}
|
||||
type="event"
|
||||
metric={<FormattedMessage id="metrics.actions" defaultMessage="Actions" />}
|
||||
metric={formatMessage(messages.actions)}
|
||||
websiteId={websiteId}
|
||||
dataFilter={eventTypeFilter}
|
||||
filterOptions={eventType === EVENT_FILTER_DEFAULT.value ? [] : [eventType]}
|
||||
renderLabel={({ x }) => <Label value={x} />}
|
||||
onDataLoad={handleDataLoad}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const Label = ({ value }) => {
|
||||
const [event, label] = value.split('\t');
|
||||
return (
|
||||
<>
|
||||
<Tag>{event}</Tag>
|
||||
{label}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
@ -1,6 +0,0 @@
|
||||
.filter {
|
||||
display: flex;
|
||||
justify-content: flex-start;
|
||||
align-items: center;
|
||||
margin-bottom: 15px;
|
||||
}
|
@ -54,9 +54,12 @@ export default function MetricsTable({
|
||||
|
||||
const filteredData = useMemo(() => {
|
||||
if (data) {
|
||||
const items = percentFilter(dataFilter ? dataFilter(data, filterOptions) : data);
|
||||
let items = percentFilter(dataFilter ? dataFilter(data, filterOptions) : data);
|
||||
if (limit) {
|
||||
return items.filter((e, i) => i < limit).sort(firstBy('y', -1).thenBy('x'));
|
||||
items = items.filter((e, i) => i < limit);
|
||||
}
|
||||
if (filterOptions?.sort === false) {
|
||||
return items;
|
||||
}
|
||||
return items.sort(firstBy('y', -1).thenBy('x'));
|
||||
}
|
||||
|
56
components/metrics/QueryParametersTable.js
Normal file
56
components/metrics/QueryParametersTable.js
Normal file
@ -0,0 +1,56 @@
|
||||
import { useState } from 'react';
|
||||
import { useIntl, defineMessages } from 'react-intl';
|
||||
import MetricsTable from './MetricsTable';
|
||||
import Tag from 'components/common/Tag';
|
||||
import { paramFilter } from 'lib/filters';
|
||||
import { safeDecodeURI } from 'lib/url';
|
||||
import FilterButtons from '../common/FilterButtons';
|
||||
|
||||
const FILTER_COMBINED = 0;
|
||||
const FILTER_RAW = 1;
|
||||
|
||||
const messages = defineMessages({
|
||||
combined: { id: 'metrics.filter.combined', defaultMessage: 'Combined' },
|
||||
raw: { id: 'metrics.filter.raw', defaultMessage: 'Raw' },
|
||||
views: { id: 'metrics.views', defaultMessage: 'Views' },
|
||||
none: { id: 'label.none', defaultMessage: 'None' },
|
||||
query: { id: 'metrics.query-parameters', defaultMessage: 'Query parameters' },
|
||||
});
|
||||
|
||||
export default function QueryParametersTable({ websiteId, showFilters, ...props }) {
|
||||
const [filter, setFilter] = useState(FILTER_COMBINED);
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
const buttons = [
|
||||
{
|
||||
label: formatMessage(messages.combined),
|
||||
value: FILTER_COMBINED,
|
||||
},
|
||||
{ label: formatMessage(messages.raw), value: FILTER_RAW },
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
{showFilters && <FilterButtons buttons={buttons} selected={filter} onClick={setFilter} />}
|
||||
<MetricsTable
|
||||
{...props}
|
||||
title={formatMessage(messages.query)}
|
||||
type="query"
|
||||
metric={formatMessage(messages.views)}
|
||||
websiteId={websiteId}
|
||||
dataFilter={filter !== FILTER_RAW ? paramFilter : null}
|
||||
renderLabel={({ x, p, v }) =>
|
||||
filter === FILTER_RAW ? (
|
||||
x
|
||||
) : (
|
||||
<>
|
||||
<Tag>{safeDecodeURI(p)}</Tag>
|
||||
{safeDecodeURI(v)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
delay={0}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
@ -3,7 +3,6 @@ import { FormattedMessage, useIntl } from 'react-intl';
|
||||
import { FixedSizeList } from 'react-window';
|
||||
import firstBy from 'thenby';
|
||||
import Icon from 'components/common/Icon';
|
||||
import Tag from 'components/common/Tag';
|
||||
import Dot from 'components/common/Dot';
|
||||
import FilterButtons from 'components/common/FilterButtons';
|
||||
import NoData from 'components/common/NoData';
|
||||
@ -92,8 +91,7 @@ export default function RealtimeLog({ data, websites, websiteId }) {
|
||||
}
|
||||
|
||||
function getDetail({
|
||||
event_type,
|
||||
event_value,
|
||||
event_name,
|
||||
view_id,
|
||||
session_id,
|
||||
url,
|
||||
@ -103,12 +101,8 @@ export default function RealtimeLog({ data, websites, websiteId }) {
|
||||
device,
|
||||
website_id,
|
||||
}) {
|
||||
if (event_type) {
|
||||
return (
|
||||
<div>
|
||||
<Tag>{event_type}</Tag> {event_value}
|
||||
</div>
|
||||
);
|
||||
if (event_name) {
|
||||
return <div>{event_name}</div>;
|
||||
}
|
||||
if (view_id) {
|
||||
const domain = getWebsite({ website_id })?.domain;
|
||||
|
@ -5,8 +5,8 @@ import FilterButtons from 'components/common/FilterButtons';
|
||||
import FilterLink from 'components/common/FilterLink';
|
||||
import { refFilter } from 'lib/filters';
|
||||
|
||||
export const FILTER_COMBINED = 0;
|
||||
export const FILTER_RAW = 1;
|
||||
const FILTER_COMBINED = 0;
|
||||
const FILTER_RAW = 1;
|
||||
|
||||
const messages = defineMessages({
|
||||
combined: { id: 'metrics.filter.combined', defaultMessage: 'Combined' },
|
||||
|
@ -6,7 +6,7 @@ export default function ScreenTable({ websiteId, ...props }) {
|
||||
return (
|
||||
<MetricsTable
|
||||
{...props}
|
||||
title={<FormattedMessage id="metrics.screens" defaultMessage="Screen" />}
|
||||
title={<FormattedMessage id="metrics.screens" defaultMessage="Screens" />}
|
||||
type="screen"
|
||||
metric={<FormattedMessage id="metrics.visitors" defaultMessage="Visitors" />}
|
||||
websiteId={websiteId}
|
||||
|
@ -1,47 +0,0 @@
|
||||
import React, { useState } from 'react';
|
||||
import { useIntl, defineMessages } from 'react-intl';
|
||||
import MetricsTable from './MetricsTable';
|
||||
import FilterButtons from 'components/common/FilterButtons';
|
||||
|
||||
export const UTM_SOURCE = 'utm_source';
|
||||
export const UTM_MEDIUM = 'utm_medium';
|
||||
export const UTM_CAMPAIGN = 'utm_campaign';
|
||||
export const UTM_CONTENT = 'utm_content';
|
||||
export const UTM_TERM = 'utm_term';
|
||||
|
||||
const messages = defineMessages({
|
||||
utm_source: { id: 'metrics.utm_source', defaultMessage: 'UTM Source' },
|
||||
utm_medium: { id: 'metrics.utm_medium', defaultMessage: 'UTM Medium' },
|
||||
utm_campaign: { id: 'metrics.utm_campaign', defaultMessage: 'UTM Campaign' },
|
||||
utm_content: { id: 'metrics.utm_content', defaultMessage: 'UTM Content' },
|
||||
utm_term: { id: 'metrics.utm_term', defaultMessage: 'UTM Term' },
|
||||
views: { id: 'metrics.views', defaultMessage: 'Views' },
|
||||
none: { id: 'label.none', defaultMessage: 'None' },
|
||||
});
|
||||
|
||||
export default function UTMTable({ websiteId, showFilters, ...props }) {
|
||||
const [type, setType] = useState(UTM_SOURCE);
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
const buttons = [
|
||||
{ label: formatMessage(messages.utm_source), value: UTM_SOURCE },
|
||||
{ label: formatMessage(messages.utm_medium), value: UTM_MEDIUM },
|
||||
{ label: formatMessage(messages.utm_campaign), value: UTM_CAMPAIGN },
|
||||
{ label: formatMessage(messages.utm_content), value: UTM_CONTENT },
|
||||
{ label: formatMessage(messages.utm_term), value: UTM_TERM },
|
||||
];
|
||||
|
||||
return (
|
||||
<>
|
||||
{showFilters && <FilterButtons buttons={buttons} selected={type} onClick={setType} />}
|
||||
<MetricsTable
|
||||
{...props}
|
||||
title={formatMessage(messages[type])}
|
||||
type={type}
|
||||
metric={formatMessage(messages.views)}
|
||||
websiteId={websiteId}
|
||||
delay={0}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
import { useState } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
import { useRouter } from 'next/router';
|
||||
import Page from 'components/layout/Page';
|
||||
import PageHeader from 'components/layout/PageHeader';
|
||||
@ -7,19 +7,24 @@ import WebsiteList from 'components/pages/WebsiteList';
|
||||
import Button from 'components/common/Button';
|
||||
import DashboardSettingsButton from 'components/settings/DashboardSettingsButton';
|
||||
import useFetch from 'hooks/useFetch';
|
||||
import useStore from 'store/app';
|
||||
import useDashboard from 'store/dashboard';
|
||||
import DashboardEdit from './DashboardEdit';
|
||||
import styles from './WebsiteList.module.css';
|
||||
|
||||
const selector = state => state.dashboard;
|
||||
const messages = defineMessages({
|
||||
dashboard: { id: 'label.dashboard', defaultMessage: 'Dashboard' },
|
||||
more: { id: 'label.more', defaultMessage: 'More' },
|
||||
});
|
||||
|
||||
export default function Dashboard() {
|
||||
const router = useRouter();
|
||||
const { id } = router.query;
|
||||
const userId = id?.[0];
|
||||
const store = useStore(selector);
|
||||
const { showCharts, limit } = store;
|
||||
const dashboard = useDashboard();
|
||||
const { showCharts, limit, editing } = dashboard;
|
||||
const [max, setMax] = useState(limit);
|
||||
const { data } = useFetch('/websites', { params: { user_id: userId } });
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
function handleMore() {
|
||||
setMax(max + limit);
|
||||
@ -32,15 +37,14 @@ export default function Dashboard() {
|
||||
return (
|
||||
<Page>
|
||||
<PageHeader>
|
||||
<div>
|
||||
<FormattedMessage id="label.dashboard" defaultMessage="Dashboard" />
|
||||
</div>
|
||||
<DashboardSettingsButton />
|
||||
<div>{formatMessage(messages.dashboard)}</div>
|
||||
{!editing && <DashboardSettingsButton />}
|
||||
</PageHeader>
|
||||
<WebsiteList websites={data} showCharts={showCharts} limit={max} />
|
||||
{editing && <DashboardEdit websites={data} />}
|
||||
{!editing && <WebsiteList websites={data} showCharts={showCharts} limit={max} />}
|
||||
{max < data.length && (
|
||||
<Button className={styles.button} onClick={handleMore}>
|
||||
<FormattedMessage id="label.more" defaultMessage="More" />
|
||||
{formatMessage(messages.more)}
|
||||
</Button>
|
||||
)}
|
||||
</Page>
|
||||
|
102
components/pages/DashboardEdit.js
Normal file
102
components/pages/DashboardEdit.js
Normal file
@ -0,0 +1,102 @@
|
||||
import { useState, useMemo } from 'react';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
import { DragDropContext, Draggable, Droppable } from 'react-beautiful-dnd';
|
||||
import classNames from 'classnames';
|
||||
import Button from 'components/common/Button';
|
||||
import { sortArrayByMap } from 'lib/array';
|
||||
import useDashboard, { saveDashboard } from 'store/dashboard';
|
||||
import styles from './DashboardEdit.module.css';
|
||||
|
||||
const messages = defineMessages({
|
||||
save: { id: 'label.save', defaultMessage: 'Save' },
|
||||
reset: { id: 'label.reset', defaultMessage: 'Reset' },
|
||||
cancel: { id: 'label.cancel', defaultMessage: 'Cancel' },
|
||||
});
|
||||
|
||||
const dragId = 'dashboard-website-ordering';
|
||||
|
||||
export default function DashboardEdit({ websites }) {
|
||||
const settings = useDashboard();
|
||||
const { websiteOrder } = settings;
|
||||
const { formatMessage } = useIntl();
|
||||
const [order, setOrder] = useState(websiteOrder || []);
|
||||
|
||||
const ordered = useMemo(() => sortArrayByMap(websites, order, 'website_id'), [websites, order]);
|
||||
|
||||
console.log({ order, ordered });
|
||||
|
||||
function handleWebsiteDrag({ destination, source }) {
|
||||
if (!destination || destination.index === source.index) return;
|
||||
|
||||
const orderedWebsites = [...ordered];
|
||||
const [removed] = orderedWebsites.splice(source.index, 1);
|
||||
orderedWebsites.splice(destination.index, 0, removed);
|
||||
|
||||
setOrder(orderedWebsites.map(({ website_id }) => website_id));
|
||||
}
|
||||
|
||||
function handleSave() {
|
||||
saveDashboard({
|
||||
editing: false,
|
||||
websiteOrder: order,
|
||||
});
|
||||
}
|
||||
|
||||
function handleCancel() {
|
||||
saveDashboard({ editing: false, websiteOrder });
|
||||
}
|
||||
|
||||
function handleReset() {
|
||||
setOrder([]);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={styles.buttons}>
|
||||
<Button onClick={handleSave} variant="action" size="small">
|
||||
{formatMessage(messages.save)}
|
||||
</Button>
|
||||
<Button onClick={handleCancel} size="small">
|
||||
{formatMessage(messages.cancel)}
|
||||
</Button>
|
||||
<Button onClick={handleReset} size="small">
|
||||
{formatMessage(messages.reset)}
|
||||
</Button>
|
||||
</div>
|
||||
<div className={styles.dragActive}>
|
||||
<DragDropContext onDragEnd={handleWebsiteDrag}>
|
||||
<Droppable droppableId={dragId}>
|
||||
{(provided, snapshot) => (
|
||||
<div
|
||||
{...provided.droppableProps}
|
||||
ref={provided.innerRef}
|
||||
style={{ marginBottom: snapshot.isDraggingOver ? 260 : null }}
|
||||
>
|
||||
{ordered.map(({ website_id, name, domain }, index) => (
|
||||
<Draggable key={website_id} draggableId={`${dragId}-${website_id}`} index={index}>
|
||||
{(provided, snapshot) => (
|
||||
<div
|
||||
ref={provided.innerRef}
|
||||
className={classNames(styles.item, {
|
||||
[styles.active]: snapshot.isDragging,
|
||||
})}
|
||||
{...provided.draggableProps}
|
||||
{...provided.dragHandleProps}
|
||||
>
|
||||
<div className={styles.text}>
|
||||
<h1>{name}</h1>
|
||||
<h2>{domain}</h2>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Draggable>
|
||||
))}
|
||||
{provided.placeholder}
|
||||
</div>
|
||||
)}
|
||||
</Droppable>
|
||||
</DragDropContext>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
40
components/pages/DashboardEdit.module.css
Normal file
40
components/pages/DashboardEdit.module.css
Normal file
@ -0,0 +1,40 @@
|
||||
.buttons {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
gap: 10px;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.item {
|
||||
padding: 5px 0;
|
||||
}
|
||||
|
||||
.item h1 {
|
||||
font-weight: 600;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.item h2 {
|
||||
font-size: 14px;
|
||||
color: var(--gray700);
|
||||
}
|
||||
|
||||
.text {
|
||||
padding: 20px;
|
||||
border-radius: 5px;
|
||||
border: 1px solid var(--gray400);
|
||||
background: var(--gray50);
|
||||
}
|
||||
|
||||
.active .text {
|
||||
border-color: var(--gray600);
|
||||
box-shadow: 4px 4px 4px var(--gray100);
|
||||
}
|
||||
|
||||
.dragActive {
|
||||
cursor: grab;
|
||||
}
|
||||
|
||||
.dragActive:active {
|
||||
cursor: grabbing;
|
||||
}
|
@ -1,4 +1,3 @@
|
||||
import React, { useState } from 'react';
|
||||
import classNames from 'classnames';
|
||||
import Head from 'next/head';
|
||||
import Link from 'next/link';
|
||||
@ -9,35 +8,37 @@ import DropDown from 'components/common/DropDown';
|
||||
import WebsiteChart from 'components/metrics/WebsiteChart';
|
||||
import EventsChart from 'components/metrics/EventsChart';
|
||||
import Button from 'components/common/Button';
|
||||
import EmptyPlaceholder from 'components/common/EmptyPlaceholder';
|
||||
import Icon from 'components/common/Icon';
|
||||
import useFetch from 'hooks/useFetch';
|
||||
import useUser from 'hooks/useUser';
|
||||
import ChevronDown from 'assets/chevron-down.svg';
|
||||
import styles from './TestConsole.module.css';
|
||||
|
||||
export default function TestConsole() {
|
||||
const { user } = useUser();
|
||||
const [website, setWebsite] = useState();
|
||||
const [show, setShow] = useState(true);
|
||||
const { basePath } = useRouter();
|
||||
const { data } = useFetch('/websites');
|
||||
const router = useRouter();
|
||||
const {
|
||||
basePath,
|
||||
query: { id },
|
||||
} = router;
|
||||
const websiteId = id?.[0];
|
||||
|
||||
if (!data || !user?.is_admin) {
|
||||
if (!data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const options = data.map(({ name, website_id }) => ({ label: name, value: website_id }));
|
||||
const website = data.find(({ website_id }) => website_id === +websiteId);
|
||||
const selectedValue = options.find(({ value }) => value === website?.website_id)?.value;
|
||||
|
||||
console.log({ websiteId, data, options, website });
|
||||
|
||||
function handleSelect(value) {
|
||||
setWebsite(data.find(({ website_id }) => website_id === value));
|
||||
router.push(`/console/${value}`);
|
||||
}
|
||||
|
||||
function handleClick() {
|
||||
window.umami('event (default)');
|
||||
window.umami('umami-default');
|
||||
window.umami.trackView('/page-view', 'https://www.google.com');
|
||||
window.umami.trackEvent('event (custom)', 'custom-type');
|
||||
window.umami.trackEvent('track-event-no-data');
|
||||
window.umami.trackEvent('track-event-with-data', { test: 'test-data', time: Date.now() });
|
||||
}
|
||||
|
||||
return (
|
||||
@ -61,43 +62,37 @@ export default function TestConsole() {
|
||||
onChange={handleSelect}
|
||||
/>
|
||||
</PageHeader>
|
||||
{!selectedValue && <EmptyPlaceholder msg="I hope you know what you're doing here" />}
|
||||
{selectedValue && (
|
||||
{website && (
|
||||
<>
|
||||
<div>
|
||||
<Icon
|
||||
icon={<ChevronDown />}
|
||||
className={classNames({ [styles.hidden]: !show })}
|
||||
onClick={() => setShow(!show)}
|
||||
/>
|
||||
</div>
|
||||
{show && (
|
||||
<div className={classNames(styles.test, 'row')}>
|
||||
<div className="col-4">
|
||||
<PageHeader>Page links</PageHeader>
|
||||
<div>
|
||||
<Link href={`?page=1`}>
|
||||
<Link href={`/console/${websiteId}?page=1`}>
|
||||
<a>page one</a>
|
||||
</Link>
|
||||
</div>
|
||||
<div>
|
||||
<Link href={`?page=2`}>
|
||||
<Link href={`/console/${websiteId}?page=2`}>
|
||||
<a>page two</a>
|
||||
</Link>
|
||||
</div>
|
||||
<div>
|
||||
<Link href={`https://www.google.com`}>
|
||||
<a className="umami--click--external-link">external link</a>
|
||||
<a className="umami--click--external-link-direct">external link (direct)</a>
|
||||
</Link>
|
||||
</div>
|
||||
<div>
|
||||
<Link href={`https://www.google.com`}>
|
||||
<a className="umami--click--external-link-tab" target="_blank">
|
||||
external link (tab)
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-4">
|
||||
<PageHeader>CSS events</PageHeader>
|
||||
<Button
|
||||
id="primary-button"
|
||||
className="umami--click--primary-button"
|
||||
variant="action"
|
||||
>
|
||||
<Button id="primary-button" className="umami--click--button-click" variant="action">
|
||||
Send event
|
||||
</Button>
|
||||
</div>
|
||||
@ -108,7 +103,6 @@ export default function TestConsole() {
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className="row">
|
||||
<div className="col-12">
|
||||
<WebsiteChart
|
||||
|
@ -1,5 +1,5 @@
|
||||
import React, { useState } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||
import classNames from 'classnames';
|
||||
import WebsiteChart from 'components/metrics/WebsiteChart';
|
||||
import WorldMap from 'components/common/WorldMap';
|
||||
@ -18,12 +18,25 @@ import CountriesTable from 'components/metrics/CountriesTable';
|
||||
import LanguagesTable from 'components/metrics/LanguagesTable';
|
||||
import EventsTable from 'components/metrics/EventsTable';
|
||||
import EventsChart from 'components/metrics/EventsChart';
|
||||
import ScreenTable from 'components/metrics/ScreenTable';
|
||||
import QueryParametersTable from 'components/metrics/QueryParametersTable';
|
||||
import useFetch from 'hooks/useFetch';
|
||||
import usePageQuery from 'hooks/usePageQuery';
|
||||
import { DEFAULT_ANIMATION_DURATION } from 'lib/constants';
|
||||
import styles from './WebsiteDetails.module.css';
|
||||
import ScreenTable from 'components/metrics/ScreenTable';
|
||||
import UTMTable from 'components/metrics/UTMTable';
|
||||
|
||||
const messages = defineMessages({
|
||||
pages: { id: 'metrics.pages', defaultMessage: 'Pages' },
|
||||
referrers: { id: 'metrics.referrers', defaultMessage: 'Referrers' },
|
||||
screens: { id: 'metrics.screens', defaultMessage: 'Screens' },
|
||||
browsers: { id: 'metrics.browsers', defaultMessage: 'Browsers' },
|
||||
os: { id: 'metrics.operating-systems', defaultMessage: 'Operating system' },
|
||||
devices: { id: 'metrics.devices', defaultMessage: 'Devices' },
|
||||
countries: { id: 'metrics.countries', defaultMessage: 'Countries' },
|
||||
languages: { id: 'metrics.languages', defaultMessage: 'Languages' },
|
||||
events: { id: 'metrics.events', defaultMessage: 'Events' },
|
||||
query: { id: 'metrics.query-parameters', defaultMessage: 'Query parameters' },
|
||||
});
|
||||
|
||||
const views = {
|
||||
url: PagesTable,
|
||||
@ -35,7 +48,7 @@ const views = {
|
||||
country: CountriesTable,
|
||||
language: LanguagesTable,
|
||||
event: EventsTable,
|
||||
utm: UTMTable,
|
||||
query: QueryParametersTable,
|
||||
};
|
||||
|
||||
export default function WebsiteDetails({ websiteId }) {
|
||||
@ -47,6 +60,7 @@ export default function WebsiteDetails({ websiteId }) {
|
||||
resolve,
|
||||
query: { view },
|
||||
} = usePageQuery();
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
const BackButton = () => (
|
||||
<div key="back-button" className={classNames(styles.backButton, 'col-12')}>
|
||||
@ -61,44 +75,44 @@ export default function WebsiteDetails({ websiteId }) {
|
||||
render: BackButton,
|
||||
},
|
||||
{
|
||||
label: <FormattedMessage id="metrics.pages" defaultMessage="Pages" />,
|
||||
label: formatMessage(messages.pages),
|
||||
value: resolve({ view: 'url' }),
|
||||
},
|
||||
{
|
||||
label: <FormattedMessage id="metrics.referrers" defaultMessage="Referrers" />,
|
||||
label: formatMessage(messages.referrers),
|
||||
value: resolve({ view: 'referrer' }),
|
||||
},
|
||||
{
|
||||
label: <FormattedMessage id="metrics.screens" defaultMessage="Screens" />,
|
||||
value: resolve({ view: 'screen' }),
|
||||
},
|
||||
{
|
||||
label: <FormattedMessage id="metrics.browsers" defaultMessage="Browsers" />,
|
||||
label: formatMessage(messages.browsers),
|
||||
value: resolve({ view: 'browser' }),
|
||||
},
|
||||
{
|
||||
label: <FormattedMessage id="metrics.operating-systems" defaultMessage="Operating system" />,
|
||||
label: formatMessage(messages.os),
|
||||
value: resolve({ view: 'os' }),
|
||||
},
|
||||
{
|
||||
label: <FormattedMessage id="metrics.devices" defaultMessage="Devices" />,
|
||||
label: formatMessage(messages.devices),
|
||||
value: resolve({ view: 'device' }),
|
||||
},
|
||||
{
|
||||
label: <FormattedMessage id="metrics.countries" defaultMessage="Countries" />,
|
||||
label: formatMessage(messages.countries),
|
||||
value: resolve({ view: 'country' }),
|
||||
},
|
||||
{
|
||||
label: <FormattedMessage id="metrics.languages" defaultMessage="Languages" />,
|
||||
label: formatMessage(messages.languages),
|
||||
value: resolve({ view: 'language' }),
|
||||
},
|
||||
{
|
||||
label: <FormattedMessage id="metrics.events" defaultMessage="Events" />,
|
||||
label: formatMessage(messages.screens),
|
||||
value: resolve({ view: 'screen' }),
|
||||
},
|
||||
{
|
||||
label: formatMessage(messages.events),
|
||||
value: resolve({ view: 'event' }),
|
||||
},
|
||||
{
|
||||
label: <FormattedMessage id="metrics.utm" defaultMessage="UTM" />,
|
||||
value: resolve({ view: 'utm' }),
|
||||
label: formatMessage(messages.query),
|
||||
value: resolve({ view: 'query' }),
|
||||
},
|
||||
];
|
||||
|
||||
|
@ -1,25 +1,42 @@
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
import Link from 'components/common/Link';
|
||||
import WebsiteChart from 'components/metrics/WebsiteChart';
|
||||
import Page from 'components/layout/Page';
|
||||
import EmptyPlaceholder from 'components/common/EmptyPlaceholder';
|
||||
import Arrow from 'assets/arrow-right.svg';
|
||||
import styles from './WebsiteList.module.css';
|
||||
import useDashboard from 'store/dashboard';
|
||||
import { sortArrayByMap } from 'lib/array';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
const messages = defineMessages({
|
||||
noWebsites: {
|
||||
id: 'message.no-websites-configured',
|
||||
defaultMessage: "You don't have any websites configured.",
|
||||
},
|
||||
goToSettngs: {
|
||||
id: 'message.go-to-settings',
|
||||
defaultMessage: 'Go to settings',
|
||||
},
|
||||
});
|
||||
|
||||
export default function WebsiteList({ websites, showCharts, limit }) {
|
||||
const { websiteOrder } = useDashboard();
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
console.log({ websiteOrder });
|
||||
|
||||
const ordered = useMemo(
|
||||
() => sortArrayByMap(websites, websiteOrder, 'website_id'),
|
||||
[websites, websiteOrder],
|
||||
);
|
||||
|
||||
if (websites.length === 0) {
|
||||
return (
|
||||
<Page>
|
||||
<EmptyPlaceholder
|
||||
msg={
|
||||
<FormattedMessage
|
||||
id="message.no-websites-configured"
|
||||
defaultMessage="You don't have any websites configured."
|
||||
/>
|
||||
}
|
||||
>
|
||||
<EmptyPlaceholder msg={formatMessage(messages.noWebsites)}>
|
||||
<Link href="/settings" icon={<Arrow />} iconRight>
|
||||
<FormattedMessage id="message.go-to-settings" defaultMessage="Go to settings" />
|
||||
{formatMessage(messages.goToSettngs)}
|
||||
</Link>
|
||||
</EmptyPlaceholder>
|
||||
</Page>
|
||||
@ -28,7 +45,7 @@ export default function WebsiteList({ websites, showCharts, limit }) {
|
||||
|
||||
return (
|
||||
<div>
|
||||
{websites.map(({ website_id, name, domain }, index) =>
|
||||
{ordered.map(({ website_id, name, domain }, index) =>
|
||||
index < limit ? (
|
||||
<div key={website_id} className={styles.website}>
|
||||
<WebsiteChart
|
||||
|
@ -1,26 +1,35 @@
|
||||
import React from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
import MenuButton from 'components/common/MenuButton';
|
||||
import Gear from 'assets/gear.svg';
|
||||
import useStore, { setDashboard, defaultDashboardConfig } from 'store/app';
|
||||
import { saveDashboard } from 'store/dashboard';
|
||||
|
||||
const selector = state => state.dashboard;
|
||||
const messages = defineMessages({
|
||||
toggleCharts: { id: 'message.toggle-charts', defaultMessage: 'Toggle charts' },
|
||||
editDashboard: { id: 'message.edit-dashboard', defaultMessage: 'Edit dashboard' },
|
||||
});
|
||||
|
||||
export default function DashboardSettingsButton() {
|
||||
const settings = useStore(selector);
|
||||
const { formatMessage } = useIntl();
|
||||
|
||||
const menuOptions = [
|
||||
{
|
||||
label: <FormattedMessage id="message.toggle-charts" defaultMessage="Toggle charts" />,
|
||||
label: formatMessage(messages.toggleCharts),
|
||||
value: 'charts',
|
||||
},
|
||||
{
|
||||
label: formatMessage(messages.editDashboard),
|
||||
value: 'order',
|
||||
},
|
||||
];
|
||||
|
||||
function handleSelect(value) {
|
||||
if (value === 'charts') {
|
||||
setDashboard({ ...defaultDashboardConfig, showCharts: !settings.showCharts });
|
||||
saveDashboard(state => ({ showCharts: !state.showCharts }));
|
||||
}
|
||||
if (value === 'order') {
|
||||
saveDashboard({ editing: true });
|
||||
}
|
||||
//setDashboard(value);
|
||||
}
|
||||
|
||||
return <MenuButton icon={<Gear />} options={menuOptions} onSelect={handleSelect} hideLabel />;
|
||||
|
5
components/settings/DashboardSettingsButton.module.css
Normal file
5
components/settings/DashboardSettingsButton.module.css
Normal file
@ -0,0 +1,5 @@
|
||||
.buttonGroup {
|
||||
display: flex;
|
||||
place-items: center;
|
||||
gap: 10px;
|
||||
}
|
@ -36,6 +36,7 @@ export default function WebsiteSettings() {
|
||||
const [showUrl, setShowUrl] = useState();
|
||||
const [saved, setSaved] = useState(0);
|
||||
const [message, setMessage] = useState();
|
||||
|
||||
const { data } = useFetch('/websites', { params: { include_all: !!user?.is_admin } }, [saved]);
|
||||
|
||||
const Buttons = row => (
|
||||
|
62
db/mysql/migrations/02_add_event_data/migration.sql
Normal file
62
db/mysql/migrations/02_add_event_data/migration.sql
Normal file
@ -0,0 +1,62 @@
|
||||
-- DropForeignKey
|
||||
ALTER TABLE `event` DROP FOREIGN KEY `event_ibfk_1`;
|
||||
ALTER TABLE `event` DROP FOREIGN KEY `event_ibfk_2`;
|
||||
|
||||
DROP INDEX `event_created_at_idx` ON `event`;
|
||||
DROP INDEX `event_session_id_idx` ON `event`;
|
||||
DROP INDEX `event_website_id_idx` ON `event`;
|
||||
|
||||
CREATE INDEX `event_old_created_at_idx` ON `event` (created_at);
|
||||
CREATE INDEX `event_old_session_id_idx` ON `event` (session_id);
|
||||
CREATE INDEX `event_old_website_id_idx` ON `event` (website_id);
|
||||
|
||||
-- RenameTable
|
||||
RENAME TABLE `event` TO `_event_old`;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `event`
|
||||
(
|
||||
`event_id` INTEGER UNSIGNED NOT NULL AUTO_INCREMENT,
|
||||
`website_id` INTEGER UNSIGNED NOT NULL,
|
||||
`session_id` INTEGER UNSIGNED NOT NULL,
|
||||
`created_at` TIMESTAMP(0) NULL DEFAULT CURRENT_TIMESTAMP(0),
|
||||
`url` VARCHAR(500) NOT NULL,
|
||||
`event_name` VARCHAR(50) NOT NULL,
|
||||
|
||||
INDEX `event_created_at_idx`(`created_at`),
|
||||
INDEX `event_session_id_idx`(`session_id`),
|
||||
INDEX `event_website_id_idx`(`website_id`),
|
||||
PRIMARY KEY (`event_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `event` ADD CONSTRAINT `event_ibfk_2` FOREIGN KEY (`session_id`) REFERENCES `session`(`session_id`) ON DELETE CASCADE ON UPDATE NO ACTION;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `event` ADD CONSTRAINT `event_ibfk_1` FOREIGN KEY (`website_id`) REFERENCES `website`(`website_id`) ON DELETE CASCADE ON UPDATE NO ACTION;
|
||||
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE `event_data` (
|
||||
`event_data_id` INTEGER NOT NULL AUTO_INCREMENT,
|
||||
`event_id` INTEGER UNSIGNED NOT NULL,
|
||||
`event_data` JSON NOT NULL,
|
||||
|
||||
UNIQUE INDEX `event_data_event_id_key`(`event_id`),
|
||||
PRIMARY KEY (`event_data_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE `event_data` ADD CONSTRAINT `event_data_event_id_fkey` FOREIGN KEY (`event_id`) REFERENCES `event`(`event_id`) ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- RenameIndex
|
||||
ALTER TABLE `account` RENAME INDEX `username` TO `account_username_key`;
|
||||
|
||||
-- RenameIndex
|
||||
ALTER TABLE `session` RENAME INDEX `session_uuid` TO `session_session_uuid_key`;
|
||||
|
||||
-- RenameIndex
|
||||
ALTER TABLE `website` RENAME INDEX `share_id` TO `website_share_id_key`;
|
||||
|
||||
-- RenameIndex
|
||||
ALTER TABLE `website` RENAME INDEX `website_uuid` TO `website_website_uuid_key`;
|
@ -9,7 +9,7 @@ datasource db {
|
||||
|
||||
model account {
|
||||
user_id Int @id @default(autoincrement()) @db.UnsignedInt
|
||||
username String @unique(map: "username") @db.VarChar(255)
|
||||
username String @unique() @db.VarChar(255)
|
||||
password String @db.VarChar(60)
|
||||
is_admin Boolean @default(false)
|
||||
created_at DateTime? @default(now()) @db.Timestamp(0)
|
||||
@ -23,16 +23,23 @@ model event {
|
||||
session_id Int @db.UnsignedInt
|
||||
created_at DateTime? @default(now()) @db.Timestamp(0)
|
||||
url String @db.VarChar(500)
|
||||
event_type String @db.VarChar(50)
|
||||
event_value String @db.VarChar(50)
|
||||
event_name String @db.VarChar(50)
|
||||
session session @relation(fields: [session_id], references: [session_id], onDelete: Cascade, onUpdate: NoAction, map: "event_ibfk_2")
|
||||
website website @relation(fields: [website_id], references: [website_id], onDelete: Cascade, onUpdate: NoAction, map: "event_ibfk_1")
|
||||
event_data event_data?
|
||||
|
||||
@@index([created_at])
|
||||
@@index([session_id])
|
||||
@@index([website_id])
|
||||
}
|
||||
|
||||
model event_data {
|
||||
event_data_id Int @id @default(autoincrement())
|
||||
event_id Int @unique @db.UnsignedInt
|
||||
event_data Json
|
||||
event event @relation(fields: [event_id], references: [event_id])
|
||||
}
|
||||
|
||||
model pageview {
|
||||
view_id Int @id @default(autoincrement()) @db.UnsignedInt
|
||||
website_id Int @db.UnsignedInt
|
||||
@ -52,7 +59,7 @@ model pageview {
|
||||
|
||||
model session {
|
||||
session_id Int @id @default(autoincrement()) @db.UnsignedInt
|
||||
session_uuid String @unique(map: "session_uuid") @db.VarChar(36)
|
||||
session_uuid String @unique() @db.VarChar(36)
|
||||
website_id Int @db.UnsignedInt
|
||||
created_at DateTime? @default(now()) @db.Timestamp(0)
|
||||
hostname String? @db.VarChar(100)
|
||||
@ -72,11 +79,11 @@ model session {
|
||||
|
||||
model website {
|
||||
website_id Int @id @default(autoincrement()) @db.UnsignedInt
|
||||
website_uuid String @unique(map: "website_uuid") @db.VarChar(36)
|
||||
website_uuid String @unique() @db.VarChar(36)
|
||||
user_id Int @db.UnsignedInt
|
||||
name String @db.VarChar(100)
|
||||
domain String? @db.VarChar(500)
|
||||
share_id String? @unique(map: "share_id") @db.VarChar(64)
|
||||
share_id String? @unique() @db.VarChar(64)
|
||||
created_at DateTime? @default(now()) @db.Timestamp(0)
|
||||
account account @relation(fields: [user_id], references: [user_id], onDelete: Cascade, onUpdate: NoAction, map: "website_ibfk_1")
|
||||
event event[]
|
||||
|
66
db/postgresql/migrations/02_add_event_data/migration.sql
Normal file
66
db/postgresql/migrations/02_add_event_data/migration.sql
Normal file
@ -0,0 +1,66 @@
|
||||
-- DropForeignKey
|
||||
ALTER TABLE "event" DROP CONSTRAINT "event_session_id_fkey";
|
||||
ALTER TABLE "event" DROP CONSTRAINT "event_website_id_fkey";
|
||||
|
||||
-- RenameIndex
|
||||
ALTER INDEX "event_pkey" RENAME TO "event_old_pkey";
|
||||
ALTER INDEX "event_created_at_idx" RENAME TO "event_old_created_at_idx";
|
||||
ALTER INDEX "event_session_id_idx" RENAME TO "event_old_session_id_idx";
|
||||
ALTER INDEX "event_website_id_idx" RENAME TO "event_old_website_id_idx";
|
||||
|
||||
-- RenameTable
|
||||
ALTER TABLE "event" RENAME TO "_event_old";
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "event" (
|
||||
"event_id" SERIAL NOT NULL,
|
||||
"website_id" INTEGER NOT NULL,
|
||||
"session_id" INTEGER NOT NULL,
|
||||
"created_at" TIMESTAMPTZ(6) DEFAULT CURRENT_TIMESTAMP,
|
||||
"url" VARCHAR(500) NOT NULL,
|
||||
"event_name" VARCHAR(50) NOT NULL,
|
||||
|
||||
PRIMARY KEY ("event_id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "event_created_at_idx" ON "event"("created_at");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "event_session_id_idx" ON "event"("session_id");
|
||||
|
||||
-- CreateIndex
|
||||
CREATE INDEX "event_website_id_idx" ON "event"("website_id");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "event" ADD CONSTRAINT "event_session_id_fkey" FOREIGN KEY ("session_id") REFERENCES "session"("session_id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "event" ADD CONSTRAINT "event_website_id_fkey" FOREIGN KEY ("website_id") REFERENCES "website"("website_id") ON DELETE CASCADE ON UPDATE CASCADE;
|
||||
|
||||
-- CreateTable
|
||||
CREATE TABLE "event_data" (
|
||||
"event_data_id" SERIAL NOT NULL,
|
||||
"event_id" INTEGER NOT NULL,
|
||||
"event_data" JSONB NOT NULL,
|
||||
|
||||
CONSTRAINT "event_data_pkey" PRIMARY KEY ("event_data_id")
|
||||
);
|
||||
|
||||
-- CreateIndex
|
||||
CREATE UNIQUE INDEX "event_data_event_id_key" ON "event_data"("event_id");
|
||||
|
||||
-- AddForeignKey
|
||||
ALTER TABLE "event_data" ADD CONSTRAINT "event_data_event_id_fkey" FOREIGN KEY ("event_id") REFERENCES "event"("event_id") ON DELETE RESTRICT ON UPDATE CASCADE;
|
||||
|
||||
-- RenameIndex
|
||||
ALTER INDEX "account.username_unique" RENAME TO "account_username_key";
|
||||
|
||||
-- RenameIndex
|
||||
ALTER INDEX "session.session_uuid_unique" RENAME TO "session_session_uuid_key";
|
||||
|
||||
-- RenameIndex
|
||||
ALTER INDEX "website.share_id_unique" RENAME TO "website_share_id_key";
|
||||
|
||||
-- RenameIndex
|
||||
ALTER INDEX "website.website_uuid_unique" RENAME TO "website_website_uuid_key";
|
@ -23,16 +23,23 @@ model event {
|
||||
session_id Int
|
||||
created_at DateTime? @default(now()) @db.Timestamptz(6)
|
||||
url String @db.VarChar(500)
|
||||
event_type String @db.VarChar(50)
|
||||
event_value String @db.VarChar(50)
|
||||
session session @relation(fields: [session_id], references: [session_id], onDelete: Cascade, onUpdate: NoAction)
|
||||
website website @relation(fields: [website_id], references: [website_id], onDelete: Cascade, onUpdate: NoAction)
|
||||
event_name String @db.VarChar(50)
|
||||
session session @relation(fields: [session_id], references: [session_id], onDelete: Cascade)
|
||||
website website @relation(fields: [website_id], references: [website_id], onDelete: Cascade)
|
||||
event_data event_data?
|
||||
|
||||
@@index([created_at])
|
||||
@@index([session_id])
|
||||
@@index([website_id])
|
||||
}
|
||||
|
||||
model event_data {
|
||||
event_data_id Int @id @default(autoincrement())
|
||||
event_id Int @unique
|
||||
event_data Json
|
||||
event event @relation(fields: [event_id], references: [event_id])
|
||||
}
|
||||
|
||||
model pageview {
|
||||
view_id Int @id @default(autoincrement())
|
||||
website_id Int
|
||||
@ -40,8 +47,8 @@ model pageview {
|
||||
created_at DateTime? @default(now()) @db.Timestamptz(6)
|
||||
url String @db.VarChar(500)
|
||||
referrer String? @db.VarChar(500)
|
||||
session session @relation(fields: [session_id], references: [session_id], onDelete: Cascade, onUpdate: NoAction)
|
||||
website website @relation(fields: [website_id], references: [website_id], onDelete: Cascade, onUpdate: NoAction)
|
||||
session session @relation(fields: [session_id], references: [session_id], onDelete: Cascade)
|
||||
website website @relation(fields: [website_id], references: [website_id], onDelete: Cascade)
|
||||
|
||||
@@index([created_at])
|
||||
@@index([session_id])
|
||||
@ -58,13 +65,13 @@ model session {
|
||||
hostname String? @db.VarChar(100)
|
||||
browser String? @db.VarChar(20)
|
||||
os String? @db.VarChar(20)
|
||||
device String? @db.VarChar(20)
|
||||
screen String? @db.VarChar(11)
|
||||
language String? @db.VarChar(35)
|
||||
country String? @db.Char(2)
|
||||
device String? @db.VarChar(20)
|
||||
website website @relation(fields: [website_id], references: [website_id], onDelete: Cascade, onUpdate: NoAction)
|
||||
event event[]
|
||||
website website @relation(fields: [website_id], references: [website_id], onDelete: Cascade)
|
||||
pageview pageview[]
|
||||
event event[]
|
||||
|
||||
@@index([created_at])
|
||||
@@index([website_id])
|
||||
@ -73,15 +80,15 @@ model session {
|
||||
model website {
|
||||
website_id Int @id @default(autoincrement())
|
||||
website_uuid String @unique @db.Uuid
|
||||
name String @db.VarChar(100)
|
||||
created_at DateTime? @default(now()) @db.Timestamptz(6)
|
||||
user_id Int
|
||||
name String @db.VarChar(100)
|
||||
domain String? @db.VarChar(500)
|
||||
share_id String? @unique(map: "website_share_id_idx") @db.VarChar(64)
|
||||
account account @relation(fields: [user_id], references: [user_id], onDelete: NoAction, onUpdate: NoAction)
|
||||
event event[]
|
||||
share_id String? @unique @db.VarChar(64)
|
||||
created_at DateTime? @default(now()) @db.Timestamptz(6)
|
||||
account account @relation(fields: [user_id], references: [user_id], onDelete: Cascade)
|
||||
pageview pageview[]
|
||||
session session[]
|
||||
event event[]
|
||||
|
||||
@@index([user_id])
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import useStore from 'store/app';
|
||||
|
||||
const selector = state => state.shareToken;
|
||||
|
||||
function parseHeaders(headers = {}, { authToken, shareToken }) {
|
||||
function parseHeaders(headers, { authToken, shareToken }) {
|
||||
if (authToken) {
|
||||
headers.authorization = `Bearer ${authToken}`;
|
||||
}
|
||||
@ -25,7 +25,7 @@ export default function useApi() {
|
||||
|
||||
return {
|
||||
get: useCallback(
|
||||
async (url, params, headers) => {
|
||||
async (url, params = {}, headers = {}) => {
|
||||
return get(
|
||||
`${basePath}/api${url}`,
|
||||
params,
|
||||
@ -36,7 +36,7 @@ export default function useApi() {
|
||||
),
|
||||
|
||||
post: useCallback(
|
||||
async (url, params, headers) => {
|
||||
async (url, params = {}, headers = {}) => {
|
||||
return post(
|
||||
`${basePath}/api${url}`,
|
||||
params,
|
||||
@ -47,7 +47,7 @@ export default function useApi() {
|
||||
),
|
||||
|
||||
put: useCallback(
|
||||
async (url, params, headers) => {
|
||||
async (url, params = {}, headers = {}) => {
|
||||
return put(
|
||||
`${basePath}/api${url}`,
|
||||
params,
|
||||
@ -58,7 +58,7 @@ export default function useApi() {
|
||||
),
|
||||
|
||||
del: useCallback(
|
||||
async (url, params, headers) => {
|
||||
async (url, params = {}, headers = {}) => {
|
||||
return del(
|
||||
`${basePath}/api${url}`,
|
||||
params,
|
||||
|
24
hooks/useConfig.js
Normal file
24
hooks/useConfig.js
Normal file
@ -0,0 +1,24 @@
|
||||
import { useEffect } from 'react';
|
||||
import useStore, { setConfig } from 'store/app';
|
||||
import useApi from 'hooks/useApi';
|
||||
|
||||
let fetched = false;
|
||||
|
||||
export default function useConfig() {
|
||||
const { config } = useStore();
|
||||
const { get } = useApi();
|
||||
|
||||
async function loadConfig() {
|
||||
const { data } = await get('/config');
|
||||
setConfig(data);
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!config && !fetched) {
|
||||
fetched = true;
|
||||
loadConfig();
|
||||
}
|
||||
}, []);
|
||||
|
||||
return config || {};
|
||||
}
|
@ -8,7 +8,9 @@
|
||||
"metrics.device.desktop",
|
||||
"metrics.device.laptop",
|
||||
"metrics.device.tablet",
|
||||
"metrics.referrers"
|
||||
"metrics.referrers",
|
||||
"metrics.utm",
|
||||
"metrics.utm_medium"
|
||||
],
|
||||
"en-GB": "*",
|
||||
"fr-FR": ["metrics.actions", "metrics.pages"],
|
||||
@ -34,5 +36,10 @@
|
||||
"metrics.device.desktop",
|
||||
"metrics.device.tablet",
|
||||
"metrics.filter.raw"
|
||||
],
|
||||
"pt-PT": [
|
||||
"label.websites",
|
||||
"metrics.device.desktop",
|
||||
"metrics.device.tablet"
|
||||
]
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
"label.add-website": "إضافة موقع",
|
||||
"label.administrator": "مدير عام؟",
|
||||
"label.all": "الكل",
|
||||
"label.all-events": "كافة الأحداث",
|
||||
"label.all-time": "All time",
|
||||
"label.all-websites": "كافة المواقع",
|
||||
"label.back": "للخلف",
|
||||
@ -68,6 +67,7 @@
|
||||
"message.confirm-reset": "هل أنت متأكد من اعادة تعيين الإحصائيات لـ {target}؟",
|
||||
"message.copied": "تم النسخ!",
|
||||
"message.delete-warning": "كافة البيانات المرتبطة سيم حذفها ايضا.",
|
||||
"message.edit-dashboard": "Edit dashboard",
|
||||
"message.failure": "حدث خطأ ما.",
|
||||
"message.get-share-url": "احصل على رابط المشاركة",
|
||||
"message.get-tracking-code": "احصل على كود التتبع",
|
||||
@ -103,15 +103,10 @@
|
||||
"metrics.operating-systems": "نظام التشغيل",
|
||||
"metrics.page-views": "مشاهدات الصفحة",
|
||||
"metrics.pages": "الصفحات",
|
||||
"metrics.query-parameters": "Query parameters",
|
||||
"metrics.referrers": "التحويلات",
|
||||
"metrics.screens": "Screens",
|
||||
"metrics.unique-visitors": "زائرون فريدون",
|
||||
"metrics.utm": "UTM",
|
||||
"metrics.utm_campaign": "UTM Campaign",
|
||||
"metrics.utm_content": "UTM Content",
|
||||
"metrics.utm_medium": "UTM Medium",
|
||||
"metrics.utm_source": "UTM Source",
|
||||
"metrics.utm_term": "UTM Term",
|
||||
"metrics.views": "مشاهدات",
|
||||
"metrics.visitors": "زوار"
|
||||
}
|
||||
|
112
lang/bn-BD.json
Normal file
112
lang/bn-BD.json
Normal file
@ -0,0 +1,112 @@
|
||||
{
|
||||
"label.accounts": "অ্যাকাউন্ট",
|
||||
"label.add-account": "অ্যাকাউন্ট যুক্ত করুন",
|
||||
"label.add-website": "ওয়েবসাইট যুক্ত করুন",
|
||||
"label.administrator": "অ্যাডমিন",
|
||||
"label.all": "সবগুলো",
|
||||
"label.all-time": "সব সময়",
|
||||
"label.all-websites": "সবগুলো ওয়েবসাইট",
|
||||
"label.back": "পেছনে",
|
||||
"label.cancel": "বাতিল",
|
||||
"label.change-password": "পাসওয়ার্ড পরিবর্তন করুন",
|
||||
"label.confirm-password": "পাসওয়ার্ড নিশ্চিত করুন",
|
||||
"label.copy-to-clipboard": "কপি করুন",
|
||||
"label.current-password": "বর্তমান পাসওয়ার্ড",
|
||||
"label.custom-range": "কাস্টম রেঞ্জ",
|
||||
"label.dashboard": "ড্যাশবোর্ড",
|
||||
"label.date-range": "তারিখের পরিসীমা",
|
||||
"label.default-date-range": "ডিফল্ট তারিখের পরিসীমা",
|
||||
"label.delete": "মুছে ফেলুন",
|
||||
"label.delete-account": "অ্যাকাউন্ট মুছুন",
|
||||
"label.delete-website": "ওয়েবসাইট মুছুন",
|
||||
"label.dismiss": "বাতিল",
|
||||
"label.domain": "ডোমেইন",
|
||||
"label.edit": "সম্পাদনা করুন",
|
||||
"label.edit-account": "অ্যাকাউন্ট সম্পাদনা করুন",
|
||||
"label.edit-website": "ওয়েবসাইট সম্পাদনা করুন",
|
||||
"label.enable-share-url": "শেয়ার ইউআরএল শেয়ার করুন",
|
||||
"label.invalid": "ভুল",
|
||||
"label.invalid-domain": "ভুল ডোমেন",
|
||||
"label.language": "ভাষা",
|
||||
"label.last-days": "শেষ {x} দিন",
|
||||
"label.last-hours": "শেষ {x} ঘন্টা",
|
||||
"label.logged-in-as": "{username} অ্যাকাউন্টে লগ ইন",
|
||||
"label.login": "লগিন",
|
||||
"label.logout": "লগ আউট",
|
||||
"label.more": "আরও",
|
||||
"label.name": "নাম",
|
||||
"label.new-password": "নতুন পাসওয়ার্ড",
|
||||
"label.none": "কিছুই না",
|
||||
"label.owner": "মালিক",
|
||||
"label.password": "পাসওয়ার্ড",
|
||||
"label.passwords-dont-match": "পাসওয়ার্ড মেলে না",
|
||||
"label.profile": "প্রোফাইল",
|
||||
"label.realtime": "সরাসরি",
|
||||
"label.realtime-logs": "সরাসরি লগ",
|
||||
"label.refresh": "রিফ্রেশ",
|
||||
"label.required": "প্রয়োজনীয়",
|
||||
"label.reset": "রিসেট",
|
||||
"label.reset-website": "ওয়েবসাইট রিসেট করুন",
|
||||
"label.save": "সংরক্ষণ",
|
||||
"label.settings": "সেটিংস",
|
||||
"label.share-url": "ইউআরএল শেয়ার করুন",
|
||||
"label.single-day": "একদিন",
|
||||
"label.theme": "থিম",
|
||||
"label.this-month": "এই মাস",
|
||||
"label.this-week": "এই সপ্তাহ",
|
||||
"label.this-year": "এই বছর",
|
||||
"label.timezone": "সময়স্থান",
|
||||
"label.today": "আজ",
|
||||
"label.tracking-code": "ট্র্যাকিং কোড",
|
||||
"label.unknown": "অজানা",
|
||||
"label.username": "ব্যবহারকারীর নাম",
|
||||
"label.view-details": "বিস্তারিত দেখুন",
|
||||
"label.websites": "সবগুলো ওয়েবসাইট",
|
||||
"message.active-users": "{x} বর্তমান {x, plural, one {visitor} other {visitors}}",
|
||||
"message.confirm-delete": "আপনি কি নিশ্চিত যে আপনি {target} মুছতে চান?",
|
||||
"message.confirm-reset": "আপনি কি নিশ্চিত যে আপনি {target} এর পরিসংখ্যান পুনরায় সেট করতে চান?",
|
||||
"message.copied": "কপি হয়েছে",
|
||||
"message.delete-warning": "সমস্ত সম্পর্কিত ডেটা পাশাপাশি মুছে ফেলা হবে।",
|
||||
"message.edit-dashboard": "Edit dashboard",
|
||||
"message.failure": "কিছু ভুল হয়েছে।",
|
||||
"message.get-share-url": "শেয়ার ইউআরএল",
|
||||
"message.get-tracking-code": "ট্র্যাকিং কোড পান",
|
||||
"message.go-to-settings": "সেটিংস এ যান",
|
||||
"message.incorrect-username-password": "ভুল ব্যবহারকারীর নাম/পাসওয়ার্ড।",
|
||||
"message.log.visitor": "{country} থেকে একজন ভিসিটর {ব্রাউজার}, ব্যবহার করছেন {os} {device} এর মধ্যে।",
|
||||
"message.new-version-available": "নতুন সংস্করণ {version} পাওয়া গিয়েছে।",
|
||||
"message.no-data-available": "কোন তথ্য নেই।",
|
||||
"message.no-websites-configured": "কোনও ওয়েবসাইট কনফিগার করা নেই।",
|
||||
"message.page-not-found": "পৃষ্ঠা খুঁজে পাওয়া যায়নি।",
|
||||
"message.powered-by": "{name} দ্বারা চালিত",
|
||||
"message.reset-warning": "এই ওয়েবসাইটের সমস্ত পরিসংখ্যান মুছে ফেলা হবে, তবে আপনার ট্র্যাকিং কোডটি অক্ষত থাকবে।",
|
||||
"message.save-success": "সংরক্ষিত হয়েছে।",
|
||||
"message.share-url": "এটি {target} এর জন্য প্রকাশ্যে শেয়ার করার ইউআরএল।",
|
||||
"message.toggle-charts": "চার্ট পরিবর্তন করুন",
|
||||
"message.track-stats": "{target} এর জন্য পরিসংখ্যানগুলি ট্র্যাক করতে, আপনার ওয়েবসাইটের {head} বিভাগে নিম্নলিখিত কোডটি রাখুন।",
|
||||
"message.type-delete": "নিশ্চিত করতে নীচের বাক্সে {delete} টাইপ করুন।",
|
||||
"message.type-reset": "নিশ্চিত করতে নীচের বাক্সে {reset} টাইপ করুন।",
|
||||
"metrics.actions": "অ্যাকশনস",
|
||||
"metrics.average-visit-time": "গড় পরিদর্শনের সময়",
|
||||
"metrics.bounce-rate": "বহিষ্কারের হার",
|
||||
"metrics.browsers": "ব্রাউজার",
|
||||
"metrics.countries": "দেশ",
|
||||
"metrics.device.desktop": "ডেস্কটপ",
|
||||
"metrics.device.laptop": "ল্যাপটপ",
|
||||
"metrics.device.mobile": "মুঠোফোন",
|
||||
"metrics.device.tablet": "ট্যাবলেট",
|
||||
"metrics.devices": "ডিভাইস গুলো",
|
||||
"metrics.events": "ঘটনা",
|
||||
"metrics.filter.combined": "সম্মিলিত",
|
||||
"metrics.filter.raw": "অপরিশোধিত",
|
||||
"metrics.languages": "ভাষা",
|
||||
"metrics.operating-systems": "অপারেটিং সিস্টেম গুলো",
|
||||
"metrics.page-views": "পৃষ্ঠা পরিদর্শন গুলো",
|
||||
"metrics.pages": "পৃষ্ঠাগুলি",
|
||||
"metrics.query-parameters": "Query parameters",
|
||||
"metrics.referrers": "রেফারার্স",
|
||||
"metrics.screens": "স্ক্রিনগুলি",
|
||||
"metrics.unique-visitors": "অনন্য ভিজিটর",
|
||||
"metrics.views": "ভিউস",
|
||||
"metrics.visitors": "পরিদর্শনার্থী"
|
||||
}
|
@ -4,7 +4,6 @@
|
||||
"label.add-website": "Afegeix lloc web",
|
||||
"label.administrator": "Administrador",
|
||||
"label.all": "Tots",
|
||||
"label.all-events": "Tots els esdeveniments",
|
||||
"label.all-time": "Sempre",
|
||||
"label.all-websites": "Tots els llocs web",
|
||||
"label.back": "Enrere",
|
||||
@ -68,6 +67,7 @@
|
||||
"message.confirm-reset": "Segur que vols restablir les estadístiques de {target}?",
|
||||
"message.copied": "S'ha copiat",
|
||||
"message.delete-warning": "També s'esborraran totes les dades relacionades.",
|
||||
"message.edit-dashboard": "Edit dashboard",
|
||||
"message.failure": "S'ha produït un error.",
|
||||
"message.get-share-url": "Obté l'enllaç per compartir",
|
||||
"message.get-tracking-code": "Obté el codi de seguiment",
|
||||
@ -103,15 +103,10 @@
|
||||
"metrics.operating-systems": "Sistemes operatius",
|
||||
"metrics.page-views": "Pàgines vistes",
|
||||
"metrics.pages": "Pàgines",
|
||||
"metrics.query-parameters": "Query parameters",
|
||||
"metrics.referrers": "Referents",
|
||||
"metrics.screens": "Screens",
|
||||
"metrics.unique-visitors": "Visitants únics",
|
||||
"metrics.utm": "UTM",
|
||||
"metrics.utm_campaign": "UTM Campaign",
|
||||
"metrics.utm_content": "UTM Content",
|
||||
"metrics.utm_medium": "UTM Medium",
|
||||
"metrics.utm_source": "UTM Source",
|
||||
"metrics.utm_term": "UTM Term",
|
||||
"metrics.views": "Vistes",
|
||||
"metrics.visitors": "Visitants"
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
"label.add-website": "Přidat web",
|
||||
"label.administrator": "Administrátor",
|
||||
"label.all": "Vše",
|
||||
"label.all-events": "All events",
|
||||
"label.all-time": "All time",
|
||||
"label.all-websites": "Všechny weby",
|
||||
"label.back": "Zpět",
|
||||
@ -68,6 +67,7 @@
|
||||
"message.confirm-reset": "Are your sure you want to reset {target}'s statistics?",
|
||||
"message.copied": "Zkopírováno!",
|
||||
"message.delete-warning": "Všechna související data budou také smazána.",
|
||||
"message.edit-dashboard": "Edit dashboard",
|
||||
"message.failure": "Něco se pokazilo.",
|
||||
"message.get-share-url": "Získat sdílené URL",
|
||||
"message.get-tracking-code": "Získat měřící kód",
|
||||
@ -103,15 +103,10 @@
|
||||
"metrics.operating-systems": "Operační systém",
|
||||
"metrics.page-views": "Zobrazení stránek",
|
||||
"metrics.pages": "Stránky",
|
||||
"metrics.query-parameters": "Query parameters",
|
||||
"metrics.referrers": "Odkazy",
|
||||
"metrics.screens": "Screens",
|
||||
"metrics.unique-visitors": "Jedinečné návštěvy",
|
||||
"metrics.utm": "UTM",
|
||||
"metrics.utm_campaign": "UTM Campaign",
|
||||
"metrics.utm_content": "UTM Content",
|
||||
"metrics.utm_medium": "UTM Medium",
|
||||
"metrics.utm_source": "UTM Source",
|
||||
"metrics.utm_term": "UTM Term",
|
||||
"metrics.views": "Zobrazení",
|
||||
"metrics.visitors": "Návštěvy"
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
"label.add-website": "Tilføj hjemmeside",
|
||||
"label.administrator": "Administrator",
|
||||
"label.all": "Alle",
|
||||
"label.all-events": "Alle hændelser",
|
||||
"label.all-time": "Altid",
|
||||
"label.all-websites": "Alle hjemmesider",
|
||||
"label.back": "Tilbage",
|
||||
@ -68,6 +67,7 @@
|
||||
"message.confirm-reset": "Er du sikker på at du ville nulstille {target}'s statistikker?",
|
||||
"message.copied": "Kopieret!",
|
||||
"message.delete-warning": "Alle tilknyttede data slettes også.",
|
||||
"message.edit-dashboard": "Edit dashboard",
|
||||
"message.failure": "Noget gik galt.",
|
||||
"message.get-share-url": "Få delings-URL",
|
||||
"message.get-tracking-code": "Få sporingskode",
|
||||
@ -103,15 +103,10 @@
|
||||
"metrics.operating-systems": "Operativsystemer",
|
||||
"metrics.page-views": "Sidevisninger",
|
||||
"metrics.pages": "Sider",
|
||||
"metrics.query-parameters": "Query parameters",
|
||||
"metrics.referrers": "Henvisninger",
|
||||
"metrics.screens": "Screens",
|
||||
"metrics.unique-visitors": "Unikke besøgende",
|
||||
"metrics.utm": "UTM",
|
||||
"metrics.utm_campaign": "UTM Campaign",
|
||||
"metrics.utm_content": "UTM Content",
|
||||
"metrics.utm_medium": "UTM Medium",
|
||||
"metrics.utm_source": "UTM Source",
|
||||
"metrics.utm_term": "UTM Term",
|
||||
"metrics.views": "Visninger",
|
||||
"metrics.visitors": "Besøgende"
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
"label.add-website": "Webseite hinzufügen",
|
||||
"label.administrator": "Administrator",
|
||||
"label.all": "Alle",
|
||||
"label.all-events": "Alle Ereignisse",
|
||||
"label.all-time": "Gesamter Zeitraum",
|
||||
"label.all-websites": "Alle Webseiten",
|
||||
"label.back": "Zurück",
|
||||
@ -37,7 +36,7 @@
|
||||
"label.more": "Mehr",
|
||||
"label.name": "Name",
|
||||
"label.new-password": "Neues Passwort",
|
||||
"label.none": "None",
|
||||
"label.none": "Keine",
|
||||
"label.owner": "Besitzer",
|
||||
"label.password": "Passwort",
|
||||
"label.passwords-dont-match": "Passwörter stimmen nicht überein",
|
||||
@ -68,6 +67,7 @@
|
||||
"message.confirm-reset": "Sind Sie sicher, dass Sie die Statistiken von {target} zurücksetzen wollen?",
|
||||
"message.copied": "In Zwischenablage kopiert!",
|
||||
"message.delete-warning": "Alle zugehörigen Daten werden ebenfalls gelöscht.",
|
||||
"message.edit-dashboard": "Edit dashboard",
|
||||
"message.failure": "Es ist ein Fehler aufgetreten.",
|
||||
"message.get-share-url": "Freigabe-URL abrufen",
|
||||
"message.get-tracking-code": "Erstelle Tracking Kennung",
|
||||
@ -103,15 +103,10 @@
|
||||
"metrics.operating-systems": "Betriebssysteme",
|
||||
"metrics.page-views": "Seitenaufrufe",
|
||||
"metrics.pages": "Seiten",
|
||||
"metrics.query-parameters": "Query parameters",
|
||||
"metrics.referrers": "Referrer",
|
||||
"metrics.screens": "Bildschirmauflösungen",
|
||||
"metrics.unique-visitors": "Eindeutige Besucher",
|
||||
"metrics.utm": "UTM",
|
||||
"metrics.utm_campaign": "UTM Campaign",
|
||||
"metrics.utm_content": "UTM Content",
|
||||
"metrics.utm_medium": "UTM Medium",
|
||||
"metrics.utm_source": "UTM Source",
|
||||
"metrics.utm_term": "UTM Term",
|
||||
"metrics.views": "Aufrufe",
|
||||
"metrics.visitors": "Besucher"
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
"label.add-website": "Προσθήκη ιστότοπου",
|
||||
"label.administrator": "Διαχειριστής",
|
||||
"label.all": "All",
|
||||
"label.all-events": "All events",
|
||||
"label.all-time": "All time",
|
||||
"label.all-websites": "All websites",
|
||||
"label.back": "Πίσω",
|
||||
@ -68,6 +67,7 @@
|
||||
"message.confirm-reset": "Are your sure you want to reset {target}'s statistics?",
|
||||
"message.copied": "Αντιγράφηκε!",
|
||||
"message.delete-warning": "Όλα τα σχετικά δεδομένα θα διαγραφούν επίσης.",
|
||||
"message.edit-dashboard": "Edit dashboard",
|
||||
"message.failure": "Κάτι πήγε στραβά.",
|
||||
"message.get-share-url": "Λήψη URL κοινής χρήσης",
|
||||
"message.get-tracking-code": "Λήψη κώδικα παρακολούθησης",
|
||||
@ -103,15 +103,10 @@
|
||||
"metrics.operating-systems": "Λειτουργικά συστήματα",
|
||||
"metrics.page-views": "Προβολές σελίδας",
|
||||
"metrics.pages": "Σελίδες",
|
||||
"metrics.query-parameters": "Query parameters",
|
||||
"metrics.referrers": "Παραπομπές",
|
||||
"metrics.screens": "Screens",
|
||||
"metrics.unique-visitors": "Μοναδικοί επισκέπτες",
|
||||
"metrics.utm": "UTM",
|
||||
"metrics.utm_campaign": "UTM Campaign",
|
||||
"metrics.utm_content": "UTM Content",
|
||||
"metrics.utm_medium": "UTM Medium",
|
||||
"metrics.utm_source": "UTM Source",
|
||||
"metrics.utm_term": "UTM Term",
|
||||
"metrics.views": "Προβολές",
|
||||
"metrics.visitors": "Επισκέπτες"
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
"label.add-website": "Add website",
|
||||
"label.administrator": "Administrator",
|
||||
"label.all": "All",
|
||||
"label.all-events": "All events",
|
||||
"label.all-time": "All time",
|
||||
"label.all-websites": "All websites",
|
||||
"label.back": "Back",
|
||||
@ -68,6 +67,7 @@
|
||||
"message.confirm-reset": "Are you sure you want to reset {target}'s statistics?",
|
||||
"message.copied": "Copied!",
|
||||
"message.delete-warning": "All associated data will be deleted as well.",
|
||||
"message.edit-dashboard": "Edit dashboard",
|
||||
"message.failure": "Something went wrong.",
|
||||
"message.get-share-url": "Get share URL",
|
||||
"message.get-tracking-code": "Get tracking code",
|
||||
@ -103,15 +103,10 @@
|
||||
"metrics.operating-systems": "Operating systems",
|
||||
"metrics.page-views": "Page views",
|
||||
"metrics.pages": "Pages",
|
||||
"metrics.query-parameters": "Query parameters",
|
||||
"metrics.referrers": "Referrers",
|
||||
"metrics.screens": "Screens",
|
||||
"metrics.unique-visitors": "Unique visitors",
|
||||
"metrics.utm": "UTM",
|
||||
"metrics.utm_campaign": "UTM Campaign",
|
||||
"metrics.utm_content": "UTM Content",
|
||||
"metrics.utm_medium": "UTM Medium",
|
||||
"metrics.utm_source": "UTM Source",
|
||||
"metrics.utm_term": "UTM Term",
|
||||
"metrics.views": "Views",
|
||||
"metrics.visitors": "Visitors"
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
"label.add-website": "Add website",
|
||||
"label.administrator": "Administrator",
|
||||
"label.all": "All",
|
||||
"label.all-events": "All events",
|
||||
"label.all-time": "All time",
|
||||
"label.all-websites": "All websites",
|
||||
"label.back": "Back",
|
||||
@ -68,6 +67,7 @@
|
||||
"message.confirm-reset": "Are you sure you want to reset {target}'s statistics?",
|
||||
"message.copied": "Copied!",
|
||||
"message.delete-warning": "All associated data will be deleted as well.",
|
||||
"message.edit-dashboard": "Edit dashboard",
|
||||
"message.failure": "Something went wrong.",
|
||||
"message.get-share-url": "Get share URL",
|
||||
"message.get-tracking-code": "Get tracking code",
|
||||
@ -103,15 +103,10 @@
|
||||
"metrics.operating-systems": "Operating systems",
|
||||
"metrics.page-views": "Page views",
|
||||
"metrics.pages": "Pages",
|
||||
"metrics.query-parameters": "Query parameters",
|
||||
"metrics.referrers": "Referrers",
|
||||
"metrics.screens": "Screens",
|
||||
"metrics.unique-visitors": "Unique visitors",
|
||||
"metrics.utm": "UTM",
|
||||
"metrics.utm_campaign": "UTM Campaign",
|
||||
"metrics.utm_content": "UTM Content",
|
||||
"metrics.utm_medium": "UTM Medium",
|
||||
"metrics.utm_source": "UTM Source",
|
||||
"metrics.utm_term": "UTM Term",
|
||||
"metrics.views": "Views",
|
||||
"metrics.visitors": "Visitors"
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
"label.add-website": "Agregar sitio",
|
||||
"label.administrator": "Administrador",
|
||||
"label.all": "Todos",
|
||||
"label.all-events": "Todos los eventos",
|
||||
"label.all-time": "Todos los tiempos",
|
||||
"label.all-websites": "Todos los sitios",
|
||||
"label.back": "Atrás",
|
||||
@ -68,6 +67,7 @@
|
||||
"message.confirm-reset": "¿Seguro que deseas restablecer las estadísticas de {target}?",
|
||||
"message.copied": "¡Copiado!",
|
||||
"message.delete-warning": "Toda la información relacionada será eliminada.",
|
||||
"message.edit-dashboard": "Edit dashboard",
|
||||
"message.failure": "Algo falló.",
|
||||
"message.get-share-url": "Obtener URL para compartir",
|
||||
"message.get-tracking-code": "Obtener código de rastreo",
|
||||
@ -103,15 +103,10 @@
|
||||
"metrics.operating-systems": "Sistemas operativos",
|
||||
"metrics.page-views": "Vistas",
|
||||
"metrics.pages": "Páginas",
|
||||
"metrics.query-parameters": "Query parameters",
|
||||
"metrics.referrers": "Referentes",
|
||||
"metrics.screens": "Screens",
|
||||
"metrics.unique-visitors": "Visitantes únicos",
|
||||
"metrics.utm": "UTM",
|
||||
"metrics.utm_campaign": "UTM Campaign",
|
||||
"metrics.utm_content": "UTM Content",
|
||||
"metrics.utm_medium": "UTM Medium",
|
||||
"metrics.utm_source": "UTM Source",
|
||||
"metrics.utm_term": "UTM Term",
|
||||
"metrics.views": "Vistas",
|
||||
"metrics.visitors": "Visitantes"
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
"label.add-website": "افزودن وبسایت",
|
||||
"label.administrator": "مدیر",
|
||||
"label.all": "همه",
|
||||
"label.all-events": "همهی رویدادها",
|
||||
"label.all-time": "همه زمان",
|
||||
"label.all-websites": "همهی وبسایتها",
|
||||
"label.back": "برگشت",
|
||||
@ -68,6 +67,7 @@
|
||||
"message.confirm-reset": "آیا از بازنشانی آمار {target} مطمئن هستید?",
|
||||
"message.copied": "کپی شد!",
|
||||
"message.delete-warning": "همهی دادههای مرتبط هم حذف خواهد شد.",
|
||||
"message.edit-dashboard": "Edit dashboard",
|
||||
"message.failure": "مشکلی پیش آمده است.",
|
||||
"message.get-share-url": "دریافت URL برای اشتراک گذاری",
|
||||
"message.get-tracking-code": "گرفتن کد رهگیری",
|
||||
@ -103,15 +103,10 @@
|
||||
"metrics.operating-systems": "سیستمعاملها",
|
||||
"metrics.page-views": "بازدید صفحه",
|
||||
"metrics.pages": "صفحهها",
|
||||
"metrics.query-parameters": "Query parameters",
|
||||
"metrics.referrers": "ارجاع دهندگان",
|
||||
"metrics.screens": "Screens",
|
||||
"metrics.unique-visitors": "بازدیدکنندههای یکتا",
|
||||
"metrics.utm": "UTM",
|
||||
"metrics.utm_campaign": "UTM Campaign",
|
||||
"metrics.utm_content": "UTM Content",
|
||||
"metrics.utm_medium": "UTM Medium",
|
||||
"metrics.utm_source": "UTM Source",
|
||||
"metrics.utm_term": "UTM Term",
|
||||
"metrics.views": "بازدید",
|
||||
"metrics.visitors": "بازدیدکننده"
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
"label.add-website": "Lisää verkkosivu",
|
||||
"label.administrator": "Järjestelmänvalvoja",
|
||||
"label.all": "Kaikki",
|
||||
"label.all-events": "Kaikki tapahtumat",
|
||||
"label.all-time": "Alusta lähtien",
|
||||
"label.all-websites": "Kaikki verkkosivut",
|
||||
"label.back": "Takaisin",
|
||||
@ -68,6 +67,7 @@
|
||||
"message.confirm-reset": "Haluatko varmasti poistaa sivuston {target} tilastot?",
|
||||
"message.copied": "Kopioitu!",
|
||||
"message.delete-warning": "Kaikki siihen liittyvät tiedot poistetaan.",
|
||||
"message.edit-dashboard": "Edit dashboard",
|
||||
"message.failure": "Jotain meni pieleen.",
|
||||
"message.get-share-url": "Hanki jakamisen URL-osoite",
|
||||
"message.get-tracking-code": "Hanki seurantakoodi",
|
||||
@ -103,15 +103,10 @@
|
||||
"metrics.operating-systems": "Käyttöjärjestelmät",
|
||||
"metrics.page-views": "Sivun näyttökerrat",
|
||||
"metrics.pages": "Sivut",
|
||||
"metrics.query-parameters": "Query parameters",
|
||||
"metrics.referrers": "Viittaajat",
|
||||
"metrics.screens": "Screens",
|
||||
"metrics.unique-visitors": "Yksittäiset kävijät",
|
||||
"metrics.utm": "UTM",
|
||||
"metrics.utm_campaign": "UTM Campaign",
|
||||
"metrics.utm_content": "UTM Content",
|
||||
"metrics.utm_medium": "UTM Medium",
|
||||
"metrics.utm_source": "UTM Source",
|
||||
"metrics.utm_term": "UTM Term",
|
||||
"metrics.views": "Näyttökerrat",
|
||||
"metrics.visitors": "Vierailijat"
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
"label.add-website": "Legg heimasíðu afturat",
|
||||
"label.administrator": "Fyrisitari",
|
||||
"label.all": "Alt",
|
||||
"label.all-events": "All events",
|
||||
"label.all-time": "All time",
|
||||
"label.all-websites": "Allar heimasíður",
|
||||
"label.back": "Aftur",
|
||||
@ -68,6 +67,7 @@
|
||||
"message.confirm-reset": "Are your sure you want to reset {target}'s statistics?",
|
||||
"message.copied": "Avrita!",
|
||||
"message.delete-warning": "Øll data ið er knýtt at verður eisini strika.",
|
||||
"message.edit-dashboard": "Edit dashboard",
|
||||
"message.failure": "Okkurt bleiv gali.",
|
||||
"message.get-share-url": "Fá leinku sum tú kanst deila",
|
||||
"message.get-tracking-code": "Fá sporings kotu",
|
||||
@ -103,15 +103,10 @@
|
||||
"metrics.operating-systems": "Stýrikervir",
|
||||
"metrics.page-views": "Opnaðar síðir",
|
||||
"metrics.pages": "Síðir",
|
||||
"metrics.query-parameters": "Query parameters",
|
||||
"metrics.referrers": "Framsendingar",
|
||||
"metrics.screens": "Screens",
|
||||
"metrics.unique-visitors": "Einsýna vitjanir",
|
||||
"metrics.utm": "UTM",
|
||||
"metrics.utm_campaign": "UTM Campaign",
|
||||
"metrics.utm_content": "UTM Content",
|
||||
"metrics.utm_medium": "UTM Medium",
|
||||
"metrics.utm_source": "UTM Source",
|
||||
"metrics.utm_term": "UTM Term",
|
||||
"metrics.views": "Sýningar",
|
||||
"metrics.visitors": "Vitjandi"
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
"label.add-website": "Ajouter un site",
|
||||
"label.administrator": "Administrateur",
|
||||
"label.all": "Tout",
|
||||
"label.all-events": "Tous les événements",
|
||||
"label.all-time": "Toutes les données",
|
||||
"label.all-websites": "Tous les sites web",
|
||||
"label.back": "Retour",
|
||||
@ -68,6 +67,7 @@
|
||||
"message.confirm-reset": "Êtes-vous sûr de vouloir réinistialiser les statistiques de {target} ?",
|
||||
"message.copied": "Copié !",
|
||||
"message.delete-warning": "Toutes les données associées seront également supprimées.",
|
||||
"message.edit-dashboard": "Edit dashboard",
|
||||
"message.failure": "Un problème est survenu.",
|
||||
"message.get-share-url": "Obtenir l'URL de partage",
|
||||
"message.get-tracking-code": "Obtenir le code de suivi",
|
||||
@ -103,15 +103,10 @@
|
||||
"metrics.operating-systems": "Systèmes d'exploitation",
|
||||
"metrics.page-views": "Pages vues",
|
||||
"metrics.pages": "Pages",
|
||||
"metrics.query-parameters": "Query parameters",
|
||||
"metrics.referrers": "Sources",
|
||||
"metrics.screens": "Tailles d'écran",
|
||||
"metrics.unique-visitors": "Visiteurs uniques",
|
||||
"metrics.utm": "UTM",
|
||||
"metrics.utm_campaign": "UTM Campaign",
|
||||
"metrics.utm_content": "UTM Content",
|
||||
"metrics.utm_medium": "UTM Medium",
|
||||
"metrics.utm_source": "UTM Source",
|
||||
"metrics.utm_term": "UTM Term",
|
||||
"metrics.views": "Vues",
|
||||
"metrics.visitors": "Visiteurs"
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
"label.add-website": "Engadir sitio web",
|
||||
"label.administrator": "Administradora",
|
||||
"label.all": "Todo",
|
||||
"label.all-events": "Tódolos eventos",
|
||||
"label.all-time": "Sempre",
|
||||
"label.all-websites": "Tódolos sitios web",
|
||||
"label.back": "Atrás",
|
||||
@ -68,6 +67,7 @@
|
||||
"message.confirm-reset": "Tes a certeza de querer restablecer as estatísticas de {target}?",
|
||||
"message.copied": "Copiado!",
|
||||
"message.delete-warning": "Tamén serán borrados tódolos datos asociados.",
|
||||
"message.edit-dashboard": "Edit dashboard",
|
||||
"message.failure": "Houbo un fallo.",
|
||||
"message.get-share-url": "Obter URL de compartición",
|
||||
"message.get-tracking-code": "Obter código de seguimento",
|
||||
@ -103,15 +103,10 @@
|
||||
"metrics.operating-systems": "Sistemas operativos",
|
||||
"metrics.page-views": "Vistas de páxinas",
|
||||
"metrics.pages": "Páxinas",
|
||||
"metrics.query-parameters": "Query parameters",
|
||||
"metrics.referrers": "Orixes",
|
||||
"metrics.screens": "Screens",
|
||||
"metrics.unique-visitors": "Visitas únicas",
|
||||
"metrics.utm": "UTM",
|
||||
"metrics.utm_campaign": "UTM Campaign",
|
||||
"metrics.utm_content": "UTM Content",
|
||||
"metrics.utm_medium": "UTM Medium",
|
||||
"metrics.utm_source": "UTM Source",
|
||||
"metrics.utm_term": "UTM Term",
|
||||
"metrics.views": "Visualizacións",
|
||||
"metrics.visitors": "Visitantes"
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
"label.add-website": "הוספת אתר",
|
||||
"label.administrator": "מנהל",
|
||||
"label.all": "הכל",
|
||||
"label.all-events": "All events",
|
||||
"label.all-time": "All time",
|
||||
"label.all-websites": "כל האתרים",
|
||||
"label.back": "חזרה",
|
||||
@ -68,6 +67,7 @@
|
||||
"message.confirm-reset": "Are your sure you want to reset {target}'s statistics?",
|
||||
"message.copied": "הועתק!",
|
||||
"message.delete-warning": "כל המידע המקושר יימחק",
|
||||
"message.edit-dashboard": "Edit dashboard",
|
||||
"message.failure": "משהו השתבש",
|
||||
"message.get-share-url": "קבלת URL שיתוף",
|
||||
"message.get-tracking-code": "קבלת קוד מעקב",
|
||||
@ -103,15 +103,10 @@
|
||||
"metrics.operating-systems": "מערכות הפעלה",
|
||||
"metrics.page-views": "צפיות בדפים",
|
||||
"metrics.pages": "דפים",
|
||||
"metrics.query-parameters": "Query parameters",
|
||||
"metrics.referrers": "מפנים",
|
||||
"metrics.screens": "Screens",
|
||||
"metrics.unique-visitors": "מבקרים ייחודיים",
|
||||
"metrics.utm": "UTM",
|
||||
"metrics.utm_campaign": "UTM Campaign",
|
||||
"metrics.utm_content": "UTM Content",
|
||||
"metrics.utm_medium": "UTM Medium",
|
||||
"metrics.utm_source": "UTM Source",
|
||||
"metrics.utm_term": "UTM Term",
|
||||
"metrics.views": "צפיות",
|
||||
"metrics.visitors": "מבקרים"
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
"label.add-website": "वेबसाइट",
|
||||
"label.administrator": "प्रशासक",
|
||||
"label.all": "सब",
|
||||
"label.all-events": "All events",
|
||||
"label.all-time": "All time",
|
||||
"label.all-websites": "सभी वेबसाइटें",
|
||||
"label.back": "पीछे",
|
||||
@ -68,6 +67,7 @@
|
||||
"message.confirm-reset": "Are your sure you want to reset {target}'s statistics?",
|
||||
"message.copied": "कॉपी हो गया!",
|
||||
"message.delete-warning": "सभी संबद्ध डेटा को भी हटा दिया जाएगा।",
|
||||
"message.edit-dashboard": "Edit dashboard",
|
||||
"message.failure": "कुछ गलत हो गया।",
|
||||
"message.get-share-url": "शेयर URL प्राप्त करें",
|
||||
"message.get-tracking-code": "ट्रैकिंग कोड प्राप्त करें",
|
||||
@ -103,15 +103,10 @@
|
||||
"metrics.operating-systems": "ऑपरेटिंग सिस्टम",
|
||||
"metrics.page-views": "पृष्ठ दृश्य",
|
||||
"metrics.pages": "पृष्ठों",
|
||||
"metrics.query-parameters": "Query parameters",
|
||||
"metrics.referrers": "सन्दर्भदाता",
|
||||
"metrics.screens": "Screens",
|
||||
"metrics.unique-visitors": "अद्वितीय आगंतुकों",
|
||||
"metrics.utm": "UTM",
|
||||
"metrics.utm_campaign": "UTM Campaign",
|
||||
"metrics.utm_content": "UTM Content",
|
||||
"metrics.utm_medium": "UTM Medium",
|
||||
"metrics.utm_source": "UTM Source",
|
||||
"metrics.utm_term": "UTM Term",
|
||||
"metrics.views": "दृश्य",
|
||||
"metrics.visitors": "आगंतुकों"
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
"label.add-website": "Weboldal hozzáadása",
|
||||
"label.administrator": "Adminisztrátor",
|
||||
"label.all": "Összes",
|
||||
"label.all-events": "Összes esemény",
|
||||
"label.all-time": "All time",
|
||||
"label.all-websites": "Összes weboldal",
|
||||
"label.back": "Vissza",
|
||||
@ -68,6 +67,7 @@
|
||||
"message.confirm-reset": "Are your sure you want to reset {target}'s statistics?",
|
||||
"message.copied": "Kimásolva!",
|
||||
"message.delete-warning": "Minden társított adat törlésre kerül.",
|
||||
"message.edit-dashboard": "Edit dashboard",
|
||||
"message.failure": "Valami baj történt.",
|
||||
"message.get-share-url": "Megosztási URL kimásolása",
|
||||
"message.get-tracking-code": "Követési kód kimásolása",
|
||||
@ -103,15 +103,10 @@
|
||||
"metrics.operating-systems": "Operációs rendszerek",
|
||||
"metrics.page-views": "Oldalmegtekintések",
|
||||
"metrics.pages": "Oldalak",
|
||||
"metrics.query-parameters": "Query parameters",
|
||||
"metrics.referrers": "Hivatkozók",
|
||||
"metrics.screens": "Screens",
|
||||
"metrics.unique-visitors": "Egyedi látogatók",
|
||||
"metrics.utm": "UTM",
|
||||
"metrics.utm_campaign": "UTM Campaign",
|
||||
"metrics.utm_content": "UTM Content",
|
||||
"metrics.utm_medium": "UTM Medium",
|
||||
"metrics.utm_source": "UTM Source",
|
||||
"metrics.utm_term": "UTM Term",
|
||||
"metrics.views": "Megtekintések",
|
||||
"metrics.visitors": "Látogatók"
|
||||
}
|
||||
|
@ -4,8 +4,7 @@
|
||||
"label.add-website": "Tambah situs web",
|
||||
"label.administrator": "Pengelola",
|
||||
"label.all": "Semua",
|
||||
"label.all-events": "Semua peristiwa",
|
||||
"label.all-time": "All time",
|
||||
"label.all-time": "Semua waktu",
|
||||
"label.all-websites": "Semua website",
|
||||
"label.back": "Kembali",
|
||||
"label.cancel": "Batal",
|
||||
@ -28,7 +27,7 @@
|
||||
"label.enable-share-url": "Aktifkan URL berbagi",
|
||||
"label.invalid": "Tidak valid",
|
||||
"label.invalid-domain": "Domain tidak valid",
|
||||
"label.language": "Language",
|
||||
"label.language": "Bahasa",
|
||||
"label.last-days": "{x} hari terakhir",
|
||||
"label.last-hours": "{x} jam terakhir",
|
||||
"label.logged-in-as": "Masuk sebagai {username}",
|
||||
@ -38,7 +37,7 @@
|
||||
"label.name": "Nama",
|
||||
"label.new-password": "Kata sandi baru",
|
||||
"label.none": "None",
|
||||
"label.owner": "Owner",
|
||||
"label.owner": "Pemilik",
|
||||
"label.password": "Kata sandi",
|
||||
"label.passwords-dont-match": "Kata sandi tidak cocok",
|
||||
"label.profile": "Profil",
|
||||
@ -52,7 +51,7 @@
|
||||
"label.settings": "Pengaturan",
|
||||
"label.share-url": "Bagikan URL",
|
||||
"label.single-day": "Sehari",
|
||||
"label.theme": "Theme",
|
||||
"label.theme": "Tema",
|
||||
"label.this-month": "Bulan ini",
|
||||
"label.this-week": "Minggu ini",
|
||||
"label.this-year": "Tahun ini",
|
||||
@ -65,9 +64,10 @@
|
||||
"label.websites": "Situs web",
|
||||
"message.active-users": "{x} pengunjung saat ini",
|
||||
"message.confirm-delete": "Apakah kamu yakin ingin menghapus {target}?",
|
||||
"message.confirm-reset": "Are your sure you want to reset {target}'s statistics?",
|
||||
"message.confirm-reset": "Anda yakin ingin mengatur ulang statistik {target}?",
|
||||
"message.copied": "Tersalin!",
|
||||
"message.delete-warning": "Semua data terkait juga akan dihapus.",
|
||||
"message.edit-dashboard": "Edit dashboard",
|
||||
"message.failure": "Ada yang salah.",
|
||||
"message.get-share-url": "Dapatkan URL berbagi",
|
||||
"message.get-tracking-code": "Dapatkan kode pelacakan",
|
||||
@ -82,8 +82,8 @@
|
||||
"message.reset-warning": "Semua statistik pada website ini akan dihapus, tetapi kode lacak akan tetap terpasang",
|
||||
"message.save-success": "Berhasil disimpan.",
|
||||
"message.share-url": "Ini adalah URL yang dibagikan secara publik untuk {target}.",
|
||||
"message.toggle-charts": "Toggle charts",
|
||||
"message.track-stats": "Untuk melacak statistik {target}, tempatkan kode berikut di bagian {head} situs web anda.",
|
||||
"message.toggle-charts": "Buka grafik",
|
||||
"message.track-stats": "Untuk melacak statistik {target}, tempatkan kode berikut di bagian {head} situs web nda.",
|
||||
"message.type-delete": "Ketikkan {delete} pada kotak di bawah untuk konfirmasi.",
|
||||
"message.type-reset": "Ketikkan {reset} pada kotak di bawah untuk konfirmasi.",
|
||||
"metrics.actions": "Aksi",
|
||||
@ -99,19 +99,14 @@
|
||||
"metrics.events": "Perihal",
|
||||
"metrics.filter.combined": "Gabungan",
|
||||
"metrics.filter.raw": "Mentah",
|
||||
"metrics.languages": "Languages",
|
||||
"metrics.languages": "Bahasa",
|
||||
"metrics.operating-systems": "Sistem Operasi",
|
||||
"metrics.page-views": "Tampilan halaman",
|
||||
"metrics.pages": "Halaman",
|
||||
"metrics.query-parameters": "Query parameters",
|
||||
"metrics.referrers": "Perujuk",
|
||||
"metrics.screens": "Screens",
|
||||
"metrics.screens": "Layar",
|
||||
"metrics.unique-visitors": "Pengunjung unik",
|
||||
"metrics.utm": "UTM",
|
||||
"metrics.utm_campaign": "UTM Campaign",
|
||||
"metrics.utm_content": "UTM Content",
|
||||
"metrics.utm_medium": "UTM Medium",
|
||||
"metrics.utm_source": "UTM Source",
|
||||
"metrics.utm_term": "UTM Term",
|
||||
"metrics.views": "Tampilan",
|
||||
"metrics.visitors": "Pengunjung"
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
"label.add-website": "Aggiungi sito",
|
||||
"label.administrator": "Amministratore",
|
||||
"label.all": "Tutto",
|
||||
"label.all-events": "Tutti gli eventi",
|
||||
"label.all-time": "Sempre",
|
||||
"label.all-websites": "Tutti i siti web",
|
||||
"label.back": "Indietro",
|
||||
@ -68,6 +67,7 @@
|
||||
"message.confirm-reset": "Sei sicuro di voler azzerare le statistiche di {target}?",
|
||||
"message.copied": "Copiato!",
|
||||
"message.delete-warning": "Saranno eliminati anche tutti i dati associati.",
|
||||
"message.edit-dashboard": "Edit dashboard",
|
||||
"message.failure": "Si è verificato un errore.",
|
||||
"message.get-share-url": "Ottieni l'URL di condivisione",
|
||||
"message.get-tracking-code": "Ottieni il codice di tracking",
|
||||
@ -103,15 +103,10 @@
|
||||
"metrics.operating-systems": "Sistemi operativi",
|
||||
"metrics.page-views": "Visualizzazioni di pagina",
|
||||
"metrics.pages": "Pagine",
|
||||
"metrics.query-parameters": "Query parameters",
|
||||
"metrics.referrers": "Referrers",
|
||||
"metrics.screens": "Screens",
|
||||
"metrics.unique-visitors": "Visitatori unici",
|
||||
"metrics.utm": "UTM",
|
||||
"metrics.utm_campaign": "UTM Campaign",
|
||||
"metrics.utm_content": "UTM Content",
|
||||
"metrics.utm_medium": "UTM Medium",
|
||||
"metrics.utm_source": "UTM Source",
|
||||
"metrics.utm_term": "UTM Term",
|
||||
"metrics.views": "Visualizzazioni",
|
||||
"metrics.visitors": "Visitatori"
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
"label.add-website": "Webサイトの追加",
|
||||
"label.administrator": "管理者",
|
||||
"label.all": "すべて表示",
|
||||
"label.all-events": "All events",
|
||||
"label.all-time": "All time",
|
||||
"label.all-websites": "すべてのWebサイト",
|
||||
"label.back": "戻る",
|
||||
@ -68,6 +67,7 @@
|
||||
"message.confirm-reset": "Are your sure you want to reset {target}'s statistics?",
|
||||
"message.copied": "コピーしました!",
|
||||
"message.delete-warning": "関連するすべてのデータも削除されます。",
|
||||
"message.edit-dashboard": "Edit dashboard",
|
||||
"message.failure": "問題が発生しました。",
|
||||
"message.get-share-url": "共有リンクを取得",
|
||||
"message.get-tracking-code": "トラッキングコードを取得",
|
||||
@ -103,15 +103,10 @@
|
||||
"metrics.operating-systems": "OS",
|
||||
"metrics.page-views": "閲覧数",
|
||||
"metrics.pages": "ページ",
|
||||
"metrics.query-parameters": "Query parameters",
|
||||
"metrics.referrers": "リファラー",
|
||||
"metrics.screens": "Screens",
|
||||
"metrics.unique-visitors": "ユニーク訪問者数",
|
||||
"metrics.utm": "UTM",
|
||||
"metrics.utm_campaign": "UTM Campaign",
|
||||
"metrics.utm_content": "UTM Content",
|
||||
"metrics.utm_medium": "UTM Medium",
|
||||
"metrics.utm_source": "UTM Source",
|
||||
"metrics.utm_term": "UTM Term",
|
||||
"metrics.views": "閲覧数",
|
||||
"metrics.visitors": "訪問者数"
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
"label.add-website": "웹사이트 추가",
|
||||
"label.administrator": "관리자",
|
||||
"label.all": "전체",
|
||||
"label.all-events": "모든 이벤트",
|
||||
"label.all-time": "All time",
|
||||
"label.all-websites": "모든 웹사이트",
|
||||
"label.back": "뒤로",
|
||||
@ -68,6 +67,7 @@
|
||||
"message.confirm-reset": "Are your sure you want to reset {target}'s statistics?",
|
||||
"message.copied": "복사했습니다!",
|
||||
"message.delete-warning": "관련된 모든 데이터도 삭제됩니다.",
|
||||
"message.edit-dashboard": "Edit dashboard",
|
||||
"message.failure": "오류가 발생하였습니다.",
|
||||
"message.get-share-url": "공유 URL 가져오기",
|
||||
"message.get-tracking-code": "추적 코드 가져오기",
|
||||
@ -103,15 +103,10 @@
|
||||
"metrics.operating-systems": "운영체제",
|
||||
"metrics.page-views": "페이지 뷰(PV)",
|
||||
"metrics.pages": "페이지",
|
||||
"metrics.query-parameters": "Query parameters",
|
||||
"metrics.referrers": "리퍼러",
|
||||
"metrics.screens": "Screens",
|
||||
"metrics.unique-visitors": "순방문자(UV)",
|
||||
"metrics.utm": "UTM",
|
||||
"metrics.utm_campaign": "UTM Campaign",
|
||||
"metrics.utm_content": "UTM Content",
|
||||
"metrics.utm_medium": "UTM Medium",
|
||||
"metrics.utm_source": "UTM Source",
|
||||
"metrics.utm_term": "UTM Term",
|
||||
"metrics.views": "조회수",
|
||||
"metrics.visitors": "방문객"
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
"label.add-website": "Pridėti svetainę",
|
||||
"label.administrator": "Administratorius",
|
||||
"label.all": "Visi",
|
||||
"label.all-events": "Visi įvykiai",
|
||||
"label.all-time": "Visas laikotarpis",
|
||||
"label.all-websites": "Visos svetainės",
|
||||
"label.back": "Atgal",
|
||||
@ -68,6 +67,7 @@
|
||||
"message.confirm-reset": "Are esate tikri, jog norite atstatyti svetainės {target} statistikos duomenis?",
|
||||
"message.copied": "Nukopijuota!",
|
||||
"message.delete-warning": "Visi susiję duomenys taip pat bus ištrinti.",
|
||||
"message.edit-dashboard": "Edit dashboard",
|
||||
"message.failure": "Kažkas įvyko ne taip.",
|
||||
"message.get-share-url": "Gauti bendrinimo nuorodą",
|
||||
"message.get-tracking-code": "Gauti sekimo kodą",
|
||||
@ -103,15 +103,10 @@
|
||||
"metrics.operating-systems": "Operacinės sistemos",
|
||||
"metrics.page-views": "Puslapių peržiūros",
|
||||
"metrics.pages": "Puslapiai",
|
||||
"metrics.query-parameters": "Query parameters",
|
||||
"metrics.referrers": "Referrers",
|
||||
"metrics.screens": "Screens",
|
||||
"metrics.unique-visitors": "Unikalūs lankytojai",
|
||||
"metrics.utm": "UTM",
|
||||
"metrics.utm_campaign": "UTM Campaign",
|
||||
"metrics.utm_content": "UTM Content",
|
||||
"metrics.utm_medium": "UTM Medium",
|
||||
"metrics.utm_source": "UTM Source",
|
||||
"metrics.utm_term": "UTM Term",
|
||||
"metrics.views": "Peržiūros",
|
||||
"metrics.visitors": "Lankytojai"
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
"label.add-website": "Веб нэмэх",
|
||||
"label.administrator": "Админ",
|
||||
"label.all": "Бүх",
|
||||
"label.all-events": "Бүх үйл явдал",
|
||||
"label.all-time": "Бүх цаг үеийн",
|
||||
"label.all-websites": "Бүх вебүүд",
|
||||
"label.back": "Буцах",
|
||||
@ -68,6 +67,7 @@
|
||||
"message.confirm-reset": "Are your sure you want to reset {target}'s statistics?",
|
||||
"message.copied": "Хуулсан!",
|
||||
"message.delete-warning": "Үүнтэй холбоотой бүх өгөгдөл устах болно.",
|
||||
"message.edit-dashboard": "Edit dashboard",
|
||||
"message.failure": "Ямар нэг зүйл буруу боллоо.",
|
||||
"message.get-share-url": "Хуваалцах холбоос авах",
|
||||
"message.get-tracking-code": "Мөрдөх код авах",
|
||||
@ -103,15 +103,10 @@
|
||||
"metrics.operating-systems": "Үйлдлийн систем",
|
||||
"metrics.page-views": "Хуудас үзсэн",
|
||||
"metrics.pages": "Хуудас",
|
||||
"metrics.query-parameters": "Query parameters",
|
||||
"metrics.referrers": "Чиглүүлэгч",
|
||||
"metrics.screens": "Screens",
|
||||
"metrics.unique-visitors": "Зочин",
|
||||
"metrics.utm": "UTM",
|
||||
"metrics.utm_campaign": "UTM Campaign",
|
||||
"metrics.utm_content": "UTM Content",
|
||||
"metrics.utm_medium": "UTM Medium",
|
||||
"metrics.utm_source": "UTM Source",
|
||||
"metrics.utm_term": "UTM Term",
|
||||
"metrics.views": "Үзсэн",
|
||||
"metrics.visitors": "Зочин"
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
"label.add-website": "Tambah laman web",
|
||||
"label.administrator": "Pentadbir",
|
||||
"label.all": "Semua",
|
||||
"label.all-events": "Semua peristiwa",
|
||||
"label.all-time": "All time",
|
||||
"label.all-websites": "Semua laman web",
|
||||
"label.back": "Kembali",
|
||||
@ -68,6 +67,7 @@
|
||||
"message.confirm-reset": "Are your sure you want to reset {target}'s statistics?",
|
||||
"message.copied": "Disalin!",
|
||||
"message.delete-warning": "Semua data yang berkaitan juga akan dihapuskan.",
|
||||
"message.edit-dashboard": "Edit dashboard",
|
||||
"message.failure": "Ada yang tidak kena.",
|
||||
"message.get-share-url": "Dapatkan URL berkongsi",
|
||||
"message.get-tracking-code": "Dapatkan kod penjejakan",
|
||||
@ -103,15 +103,10 @@
|
||||
"metrics.operating-systems": "Sistem operasi",
|
||||
"metrics.page-views": "Paparan halaman",
|
||||
"metrics.pages": "Halaman",
|
||||
"metrics.query-parameters": "Query parameters",
|
||||
"metrics.referrers": "Perujuk",
|
||||
"metrics.screens": "Screens",
|
||||
"metrics.unique-visitors": "Pelawat unik",
|
||||
"metrics.utm": "UTM",
|
||||
"metrics.utm_campaign": "UTM Campaign",
|
||||
"metrics.utm_content": "UTM Content",
|
||||
"metrics.utm_medium": "UTM Medium",
|
||||
"metrics.utm_source": "UTM Source",
|
||||
"metrics.utm_term": "UTM Term",
|
||||
"metrics.views": "Lawatan",
|
||||
"metrics.visitors": "Pelawat"
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
"label.add-website": "Legg til nettsted",
|
||||
"label.administrator": "Administrator",
|
||||
"label.all": "Alle",
|
||||
"label.all-events": "Alle hendelser",
|
||||
"label.all-time": "Noensinne",
|
||||
"label.all-websites": "Alle nettsteder",
|
||||
"label.back": "Tilbake",
|
||||
@ -68,6 +67,7 @@
|
||||
"message.confirm-reset": "Er du sikker på at du vil nullstille {target}'s statistikk?",
|
||||
"message.copied": "Kopiert!",
|
||||
"message.delete-warning": "Alle tilknyttede data slettes også.",
|
||||
"message.edit-dashboard": "Edit dashboard",
|
||||
"message.failure": "Noe gikk galt.",
|
||||
"message.get-share-url": "Få delings-URL",
|
||||
"message.get-tracking-code": "Få sporingskode",
|
||||
@ -103,15 +103,10 @@
|
||||
"metrics.operating-systems": "Operativsystemer",
|
||||
"metrics.page-views": "Sidevisninger",
|
||||
"metrics.pages": "Sider",
|
||||
"metrics.query-parameters": "Query parameters",
|
||||
"metrics.referrers": "Referanser",
|
||||
"metrics.screens": "Screens",
|
||||
"metrics.unique-visitors": "Unike besøkende",
|
||||
"metrics.utm": "UTM",
|
||||
"metrics.utm_campaign": "UTM Campaign",
|
||||
"metrics.utm_content": "UTM Content",
|
||||
"metrics.utm_medium": "UTM Medium",
|
||||
"metrics.utm_source": "UTM Source",
|
||||
"metrics.utm_term": "UTM Term",
|
||||
"metrics.views": "Visninger",
|
||||
"metrics.visitors": "Besøkende"
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
"label.add-website": "Website toevoegen",
|
||||
"label.administrator": "Administrator",
|
||||
"label.all": "Alles",
|
||||
"label.all-events": "Alle gebeurtenissen",
|
||||
"label.all-time": "Onbeperkt",
|
||||
"label.all-websites": "Alle websites",
|
||||
"label.back": "Terug",
|
||||
@ -68,6 +67,7 @@
|
||||
"message.confirm-reset": "Weet je zeker dat je de statistieken van {target} opnieuw wilt instellen?",
|
||||
"message.copied": "Gekopiëerd!",
|
||||
"message.delete-warning": "Alle verwante gegezens zullen ook verwijderd worden.",
|
||||
"message.edit-dashboard": "Edit dashboard",
|
||||
"message.failure": "Er is iets misgegaan.",
|
||||
"message.get-share-url": "Openbare URL",
|
||||
"message.get-tracking-code": "Tracking code",
|
||||
@ -103,15 +103,10 @@
|
||||
"metrics.operating-systems": "Besturingssystemen",
|
||||
"metrics.page-views": "Paginaweergaven",
|
||||
"metrics.pages": "Pagina's",
|
||||
"metrics.query-parameters": "Query parameters",
|
||||
"metrics.referrers": "Verwijzers",
|
||||
"metrics.screens": "Schermen",
|
||||
"metrics.unique-visitors": "Unieke bezoekers",
|
||||
"metrics.utm": "UTM",
|
||||
"metrics.utm_campaign": "UTM Campaign",
|
||||
"metrics.utm_content": "UTM Content",
|
||||
"metrics.utm_medium": "UTM Medium",
|
||||
"metrics.utm_source": "UTM Source",
|
||||
"metrics.utm_term": "UTM Term",
|
||||
"metrics.views": "Weergaven",
|
||||
"metrics.visitors": "Bezoekers"
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
"label.add-website": "Dodaj witrynę",
|
||||
"label.administrator": "Administrator",
|
||||
"label.all": "Wszystkie",
|
||||
"label.all-events": "Wszystkie wydarzenia",
|
||||
"label.all-time": "Cały czas",
|
||||
"label.all-websites": "Wszystkie witryny",
|
||||
"label.back": "Powrót",
|
||||
@ -68,6 +67,7 @@
|
||||
"message.confirm-reset": "Czy na pewno chcesz zresetować statystyki {target}?",
|
||||
"message.copied": "Skopiowano!",
|
||||
"message.delete-warning": "Wszystkie powiązane dane również zostaną usunięte.",
|
||||
"message.edit-dashboard": "Edit dashboard",
|
||||
"message.failure": "Coś poszło nie tak.",
|
||||
"message.get-share-url": "Uzyskaj adres URL udostępniania",
|
||||
"message.get-tracking-code": "Pobierz kod śledzenia",
|
||||
@ -103,15 +103,10 @@
|
||||
"metrics.operating-systems": "System operacyjny",
|
||||
"metrics.page-views": "Wyświetlenia strony",
|
||||
"metrics.pages": "Strony",
|
||||
"metrics.query-parameters": "Query parameters",
|
||||
"metrics.referrers": "Źródła odsyłające",
|
||||
"metrics.screens": "Ekrany",
|
||||
"metrics.unique-visitors": "Unikalni odwiedzający",
|
||||
"metrics.utm": "Kampanie UTM",
|
||||
"metrics.utm_campaign": "Kampania",
|
||||
"metrics.utm_content": "Treść",
|
||||
"metrics.utm_medium": "Medium",
|
||||
"metrics.utm_source": "Źródło",
|
||||
"metrics.utm_term": "Słowa kluczowe",
|
||||
"metrics.views": "Wyświetlenia",
|
||||
"metrics.visitors": "Odwiedzający"
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
"label.add-website": "Adicionar site",
|
||||
"label.administrator": "Administrador",
|
||||
"label.all": "Todos",
|
||||
"label.all-events": "Todos os eventos",
|
||||
"label.all-time": "Todo o período",
|
||||
"label.all-websites": "Todos os sites",
|
||||
"label.back": "Voltar",
|
||||
@ -68,6 +67,7 @@
|
||||
"message.confirm-reset": "Você tem certeza que deseja redefinir as estatísticas de {target}?",
|
||||
"message.copied": "Copiado!",
|
||||
"message.delete-warning": "Todos os dados associados também serão eliminados.",
|
||||
"message.edit-dashboard": "Edit dashboard",
|
||||
"message.failure": "Ocorreu um erro.",
|
||||
"message.get-share-url": "Obter link de compartilhamento",
|
||||
"message.get-tracking-code": "Obter código de rastreamento",
|
||||
@ -103,15 +103,10 @@
|
||||
"metrics.operating-systems": "Sistemas operacionais",
|
||||
"metrics.page-views": "Visualizações de página",
|
||||
"metrics.pages": "Páginas",
|
||||
"metrics.query-parameters": "Query parameters",
|
||||
"metrics.referrers": "Referências",
|
||||
"metrics.screens": "Screens",
|
||||
"metrics.unique-visitors": "Visitantes únicos",
|
||||
"metrics.utm": "UTM",
|
||||
"metrics.utm_campaign": "UTM Campaign",
|
||||
"metrics.utm_content": "UTM Content",
|
||||
"metrics.utm_medium": "UTM Medium",
|
||||
"metrics.utm_source": "UTM Source",
|
||||
"metrics.utm_term": "UTM Term",
|
||||
"metrics.views": "Visualizações",
|
||||
"metrics.visitors": "Visitantes"
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
"label.add-website": "Adicionar website",
|
||||
"label.administrator": "Administrador",
|
||||
"label.all": "Todos",
|
||||
"label.all-events": "Todos os eventos",
|
||||
"label.all-time": "Todo o tempo",
|
||||
"label.all-websites": "Todos os websites",
|
||||
"label.back": "Voltar",
|
||||
@ -28,7 +27,7 @@
|
||||
"label.enable-share-url": "Ativar link de partilha",
|
||||
"label.invalid": "Inválido",
|
||||
"label.invalid-domain": "Domínio inválido",
|
||||
"label.language": "Language",
|
||||
"label.language": "Língua",
|
||||
"label.last-days": "Últimos {x} dias",
|
||||
"label.last-hours": "Últimas {x} horas",
|
||||
"label.logged-in-as": "Sessão iniciada como {username}",
|
||||
@ -52,7 +51,7 @@
|
||||
"label.settings": "Definições",
|
||||
"label.share-url": "Partilhar link",
|
||||
"label.single-day": "Dia único",
|
||||
"label.theme": "Theme",
|
||||
"label.theme": "Tema",
|
||||
"label.this-month": "Este mês",
|
||||
"label.this-week": "Esta semana",
|
||||
"label.this-year": "Este ano",
|
||||
@ -68,6 +67,7 @@
|
||||
"message.confirm-reset": "Tem a certeza que pretende restaurar as estatísticas de {target}?",
|
||||
"message.copied": "Copiado!",
|
||||
"message.delete-warning": "Todos os dados associados também serão eliminados.",
|
||||
"message.edit-dashboard": "Edit dashboard",
|
||||
"message.failure": "Ocorreu um erro.",
|
||||
"message.get-share-url": "Obter link de partilha",
|
||||
"message.get-tracking-code": "Obter código de rastreamento",
|
||||
@ -103,15 +103,10 @@
|
||||
"metrics.operating-systems": "Sistemas operativos",
|
||||
"metrics.page-views": "Visualizações da página",
|
||||
"metrics.pages": "Páginas",
|
||||
"metrics.query-parameters": "Query parameters",
|
||||
"metrics.referrers": "Referenciadores",
|
||||
"metrics.screens": "Screens",
|
||||
"metrics.unique-visitors": "Visitantes únicos",
|
||||
"metrics.utm": "UTM",
|
||||
"metrics.utm_campaign": "UTM Campaign",
|
||||
"metrics.utm_content": "UTM Content",
|
||||
"metrics.utm_medium": "UTM Medium",
|
||||
"metrics.utm_source": "UTM Source",
|
||||
"metrics.utm_term": "UTM Term",
|
||||
"metrics.views": "Visualizações",
|
||||
"metrics.visitors": "Visitantes"
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
"label.add-website": "Adăugare site web",
|
||||
"label.administrator": "Administrator",
|
||||
"label.all": "Toate",
|
||||
"label.all-events": "Toate evenimentele",
|
||||
"label.all-time": "All time",
|
||||
"label.all-websites": "Toate site-urile web",
|
||||
"label.back": "Înapoi",
|
||||
@ -68,6 +67,7 @@
|
||||
"message.confirm-reset": "Sunteți sigur că doriți să resetați statisticile pentru {target}?",
|
||||
"message.copied": "Copiat!",
|
||||
"message.delete-warning": "Toate datele asociate vor fi șterse, de asemenea.",
|
||||
"message.edit-dashboard": "Edit dashboard",
|
||||
"message.failure": "Ceva n-a mers bine.",
|
||||
"message.get-share-url": "Obține adresa URL de partajare",
|
||||
"message.get-tracking-code": "Obține codul de urmărire",
|
||||
@ -103,15 +103,10 @@
|
||||
"metrics.operating-systems": "Sisteme de operare",
|
||||
"metrics.page-views": "Vizualizări de pagină",
|
||||
"metrics.pages": "Pagini",
|
||||
"metrics.query-parameters": "Query parameters",
|
||||
"metrics.referrers": "Site-uri de proveniență",
|
||||
"metrics.screens": "Screens",
|
||||
"metrics.unique-visitors": "Vizitatori unici",
|
||||
"metrics.utm": "UTM",
|
||||
"metrics.utm_campaign": "UTM Campaign",
|
||||
"metrics.utm_content": "UTM Content",
|
||||
"metrics.utm_medium": "UTM Medium",
|
||||
"metrics.utm_source": "UTM Source",
|
||||
"metrics.utm_term": "UTM Term",
|
||||
"metrics.views": "Vizualizări",
|
||||
"metrics.visitors": "Vizitatori"
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
"label.add-website": "Добавить сайт",
|
||||
"label.administrator": "Администратор",
|
||||
"label.all": "Все",
|
||||
"label.all-events": "Все события",
|
||||
"label.all-time": "Все время",
|
||||
"label.all-websites": "Все сайты",
|
||||
"label.back": "Назад",
|
||||
@ -68,6 +67,7 @@
|
||||
"message.confirm-reset": "Вы уверены, что хотите сбросить статистику {target}?",
|
||||
"message.copied": "Скопировано!",
|
||||
"message.delete-warning": "Все связанные данные будут также удалены.",
|
||||
"message.edit-dashboard": "Edit dashboard",
|
||||
"message.failure": "Что-то пошло не так.",
|
||||
"message.get-share-url": "Получить публичную ссылку",
|
||||
"message.get-tracking-code": "Получить код отслеживания",
|
||||
@ -103,15 +103,10 @@
|
||||
"metrics.operating-systems": "Операционные системы",
|
||||
"metrics.page-views": "Просмотры страниц",
|
||||
"metrics.pages": "Страницы",
|
||||
"metrics.query-parameters": "Query parameters",
|
||||
"metrics.referrers": "Источники",
|
||||
"metrics.screens": "Screens",
|
||||
"metrics.unique-visitors": "Уникальные посетители",
|
||||
"metrics.utm": "UTM",
|
||||
"metrics.utm_campaign": "UTM Campaign",
|
||||
"metrics.utm_content": "UTM Content",
|
||||
"metrics.utm_medium": "UTM Medium",
|
||||
"metrics.utm_source": "UTM Source",
|
||||
"metrics.utm_term": "UTM Term",
|
||||
"metrics.views": "Просмотры",
|
||||
"metrics.visitors": "Посетители"
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
"label.add-website": "Pridať web",
|
||||
"label.administrator": "Administrátor",
|
||||
"label.all": "Všetko",
|
||||
"label.all-events": "All events",
|
||||
"label.all-time": "All time",
|
||||
"label.all-websites": "Všetky weby",
|
||||
"label.back": "Späť",
|
||||
@ -68,6 +67,7 @@
|
||||
"message.confirm-reset": "Are your sure you want to reset {target}'s statistics?",
|
||||
"message.copied": "Skopírované!",
|
||||
"message.delete-warning": "Všetky príbuzné data budu tiež zmazané.",
|
||||
"message.edit-dashboard": "Edit dashboard",
|
||||
"message.failure": "Niečo sa pokazilo.",
|
||||
"message.get-share-url": "Získať zdielané URL",
|
||||
"message.get-tracking-code": "Získať tracking kód",
|
||||
@ -103,15 +103,10 @@
|
||||
"metrics.operating-systems": "Operačný systém",
|
||||
"metrics.page-views": "Zobrazenie stánok",
|
||||
"metrics.pages": "Stránky",
|
||||
"metrics.query-parameters": "Query parameters",
|
||||
"metrics.referrers": "Odkazy",
|
||||
"metrics.screens": "Screens",
|
||||
"metrics.unique-visitors": "Jedinečné návštevy",
|
||||
"metrics.utm": "UTM",
|
||||
"metrics.utm_campaign": "UTM Campaign",
|
||||
"metrics.utm_content": "UTM Content",
|
||||
"metrics.utm_medium": "UTM Medium",
|
||||
"metrics.utm_source": "UTM Source",
|
||||
"metrics.utm_term": "UTM Term",
|
||||
"metrics.views": "Zobrazení",
|
||||
"metrics.visitors": "Návštevy"
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
"label.add-website": "Dodaj spletno mesto",
|
||||
"label.administrator": "Administrator",
|
||||
"label.all": "Vse",
|
||||
"label.all-events": "Vsi dogodki",
|
||||
"label.all-time": "All time",
|
||||
"label.all-websites": "Vsa spletna mesta",
|
||||
"label.back": "Nazaj",
|
||||
@ -68,6 +67,7 @@
|
||||
"message.confirm-reset": "Are your sure you want to reset {target}'s statistics?",
|
||||
"message.copied": "Kopirano!",
|
||||
"message.delete-warning": "Izbrisani bodo tudi vsi povezani podatki.",
|
||||
"message.edit-dashboard": "Edit dashboard",
|
||||
"message.failure": "Prišlo je do napake.",
|
||||
"message.get-share-url": "Pridobi URL za skupno rabo",
|
||||
"message.get-tracking-code": "Pridobi kodo za sledenje",
|
||||
@ -103,15 +103,10 @@
|
||||
"metrics.operating-systems": "Operacijski sistemi",
|
||||
"metrics.page-views": "Ogledi strani",
|
||||
"metrics.pages": "Strani",
|
||||
"metrics.query-parameters": "Query parameters",
|
||||
"metrics.referrers": "Viri",
|
||||
"metrics.screens": "Screens",
|
||||
"metrics.unique-visitors": "Unikatni obiskovalci",
|
||||
"metrics.utm": "UTM",
|
||||
"metrics.utm_campaign": "UTM Campaign",
|
||||
"metrics.utm_content": "UTM Content",
|
||||
"metrics.utm_medium": "UTM Medium",
|
||||
"metrics.utm_source": "UTM Source",
|
||||
"metrics.utm_term": "UTM Term",
|
||||
"metrics.views": "Ogledi",
|
||||
"metrics.visitors": "Obiskovalci"
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
"label.add-website": "Lägg till webbsajt",
|
||||
"label.administrator": "Administratör",
|
||||
"label.all": "Alla",
|
||||
"label.all-events": "Alla händelser",
|
||||
"label.all-time": "Sedan början",
|
||||
"label.all-websites": "Alla sajter",
|
||||
"label.back": "Tillbaka",
|
||||
@ -68,6 +67,7 @@
|
||||
"message.confirm-reset": "Är du säker på att du vill återställa statistiken för {target}?",
|
||||
"message.copied": "Kopierad!",
|
||||
"message.delete-warning": "All tillhörande data kommer också raderas.",
|
||||
"message.edit-dashboard": "Edit dashboard",
|
||||
"message.failure": "Något gick fel.",
|
||||
"message.get-share-url": "Visa delnings-URL",
|
||||
"message.get-tracking-code": "Visa spårningskod",
|
||||
@ -103,15 +103,10 @@
|
||||
"metrics.operating-systems": "Operativsystem",
|
||||
"metrics.page-views": "Sidvisningar",
|
||||
"metrics.pages": "Sidor",
|
||||
"metrics.query-parameters": "Query parameters",
|
||||
"metrics.referrers": "Hänvisare",
|
||||
"metrics.screens": "Screens",
|
||||
"metrics.unique-visitors": "Unika besökare",
|
||||
"metrics.utm": "UTM",
|
||||
"metrics.utm_campaign": "UTM Campaign",
|
||||
"metrics.utm_content": "UTM Content",
|
||||
"metrics.utm_medium": "UTM Medium",
|
||||
"metrics.utm_source": "UTM Source",
|
||||
"metrics.utm_term": "UTM Term",
|
||||
"metrics.views": "Visningar",
|
||||
"metrics.visitors": "Besökare"
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
"label.add-website": "வலைத்தளத்தைச் சேர்க்க",
|
||||
"label.administrator": "நிர்வாகியைச் சேர்க்க",
|
||||
"label.all": "எல்லாம்",
|
||||
"label.all-events": "அனைத்து நிகழ்வுகளும்",
|
||||
"label.all-time": "All time",
|
||||
"label.all-websites": "அனைத்து வலைத்தளங்களும்",
|
||||
"label.back": "பின்னால்",
|
||||
@ -68,6 +67,7 @@
|
||||
"message.confirm-reset": "Are your sure you want to reset {target}'s statistics?",
|
||||
"message.copied": "நகலெடுக்கப்பட்டது!",
|
||||
"message.delete-warning": "தொடர்புடைய எல்லா தரவும் நீக்கப்படும்.",
|
||||
"message.edit-dashboard": "Edit dashboard",
|
||||
"message.failure": "ஏதோ தவறு நடந்துவிட்டது.",
|
||||
"message.get-share-url": "கள முகவரியை ஐப் பெறுக",
|
||||
"message.get-tracking-code": "கண்காணிப்பு குறியீட்டைப் பெறுக",
|
||||
@ -103,15 +103,10 @@
|
||||
"metrics.operating-systems": "இயக்க முறைமைகள்",
|
||||
"metrics.page-views": "பக்க காட்சிகள்",
|
||||
"metrics.pages": "பக்கங்கள்",
|
||||
"metrics.query-parameters": "Query parameters",
|
||||
"metrics.referrers": "குறிப்பிடுவோர்",
|
||||
"metrics.screens": "Screens",
|
||||
"metrics.unique-visitors": "தனிப்பட்ட பார்வையாளர்கள்",
|
||||
"metrics.utm": "UTM",
|
||||
"metrics.utm_campaign": "UTM Campaign",
|
||||
"metrics.utm_content": "UTM Content",
|
||||
"metrics.utm_medium": "UTM Medium",
|
||||
"metrics.utm_source": "UTM Source",
|
||||
"metrics.utm_term": "UTM Term",
|
||||
"metrics.views": "பார்வைகள்",
|
||||
"metrics.visitors": "பார்வையாளர்கள்"
|
||||
}
|
||||
|
112
lang/th-TH.json
Normal file
112
lang/th-TH.json
Normal file
@ -0,0 +1,112 @@
|
||||
{
|
||||
"label.accounts": "บัญชี",
|
||||
"label.add-account": "เพิ่มบัญชี",
|
||||
"label.add-website": "เพิ่มเว็บไซต์",
|
||||
"label.administrator": "ผู้ดูแลระบบ",
|
||||
"label.all": "ทั้งหมด",
|
||||
"label.all-time": "ทุกช่วงเวลา",
|
||||
"label.all-websites": "เว็บไซต์ทั้งหมด",
|
||||
"label.back": "ย้อนกลับ",
|
||||
"label.cancel": "ยกเลิก",
|
||||
"label.change-password": "เปลี่ยนรหัสผ่าน",
|
||||
"label.confirm-password": "ยืนยันรหัสผ่าน",
|
||||
"label.copy-to-clipboard": "คัดลอกไปยังคลิปบอร์ด",
|
||||
"label.current-password": "รหัสผ่านปัจจุบัน",
|
||||
"label.custom-range": "กำหนดช่วงเวลา",
|
||||
"label.dashboard": "แดชบอร์ด",
|
||||
"label.date-range": "ตั้งแต่วันที่",
|
||||
"label.default-date-range": "ช่วงเวลา",
|
||||
"label.delete": "ลบ",
|
||||
"label.delete-account": "ลบบัญชี",
|
||||
"label.delete-website": "ลบเว็บไซต์",
|
||||
"label.dismiss": "ยกเลิก",
|
||||
"label.domain": "โดเมน",
|
||||
"label.edit": "แก้ไข",
|
||||
"label.edit-account": "แก้ไขบัญชี",
|
||||
"label.edit-website": "แก้ไขเว็บไซต์",
|
||||
"label.enable-share-url": "เปิดใช้งานการแชร์ลิงก์",
|
||||
"label.invalid": "ไม่ถูกต้อง",
|
||||
"label.invalid-domain": "โดเมนไม่ถูกต้อง",
|
||||
"label.language": "ภาษา",
|
||||
"label.last-days": "{x} วันที่ผ่านมา",
|
||||
"label.last-hours": "{x} ชั่วโมงที่ผ่านมา",
|
||||
"label.logged-in-as": "เข้าสู่ระบบโดย {username}",
|
||||
"label.login": "เข้าสู่ระบบ",
|
||||
"label.logout": "ออกจากระบบ",
|
||||
"label.more": "เพิ่มเติม",
|
||||
"label.name": "ชื่อ",
|
||||
"label.new-password": "รหัสผ่านใหม่",
|
||||
"label.none": "ไม่ได้กำหนด",
|
||||
"label.owner": "เจ้าของ",
|
||||
"label.password": "รหัสผ่าน",
|
||||
"label.passwords-dont-match": "รหัสผ่านไม่ตรงกัน",
|
||||
"label.profile": "โปรไฟล์",
|
||||
"label.realtime": "เรียลไทม์",
|
||||
"label.realtime-logs": "Log แบบเรียลไทม์",
|
||||
"label.refresh": "รีเฟรช",
|
||||
"label.required": "ต้องการ",
|
||||
"label.reset": "รีเซต",
|
||||
"label.reset-website": "รีเซตข้อมูลสถิติ",
|
||||
"label.save": "บันทึก",
|
||||
"label.settings": "ตั้งค่า",
|
||||
"label.share-url": "แชร์ลิงก์",
|
||||
"label.single-day": "วันที่",
|
||||
"label.theme": "ธีม",
|
||||
"label.this-month": "เดือนปัจจุบัน",
|
||||
"label.this-week": "สัปดาห์ปัจจุบัน",
|
||||
"label.this-year": "ปีปัจจุบัน",
|
||||
"label.timezone": "เขตเวลา",
|
||||
"label.today": "วันนี้",
|
||||
"label.tracking-code": "โค้ดสำหรับใช้ติดตาม",
|
||||
"label.unknown": "ไม่รู้จัก",
|
||||
"label.username": "ชื่อผู้ใช้",
|
||||
"label.view-details": "แสดงรายละเอียด",
|
||||
"label.websites": "เว็บไซต์",
|
||||
"message.active-users": "มีผู้ใช้งาน {x} {x, plural, one {คนในขณะนี้} other {คนในขณะนี้}}",
|
||||
"message.confirm-delete": "คุณแน่ใจหรือไม่ว่าต้องการลบ {target} ?",
|
||||
"message.confirm-reset": "คุณแน่ใจหรือไม่ว่าต้องการรีเซตข้อมูลสถิติของ {target} ?",
|
||||
"message.copied": "คัดลอกแล้ว!",
|
||||
"message.delete-warning": "ข้อมูลที่เกี่ยวข้องทั้งหมดจะถูกลบ.",
|
||||
"message.edit-dashboard": "Edit dashboard",
|
||||
"message.failure": "เกิดข้อผิดพลาด.",
|
||||
"message.get-share-url": "รับลิงก์สำหรับแชร์",
|
||||
"message.get-tracking-code": "รับโค้ดสำหรับใช้ติดตาม",
|
||||
"message.go-to-settings": "ไปที่การตั้งค่า",
|
||||
"message.incorrect-username-password": "ชื่อผู้ใช้หรือรหัสผ่านไม่ถูกต้อง.",
|
||||
"message.log.visitor": "ผู้เข้าชมจาก {country} กำลังใช้งานผ่าน {browser} บน {os} {device}",
|
||||
"message.new-version-available": "umami เวอร์ชันใหม่ ({version}) มาแล้ว!",
|
||||
"message.no-data-available": "ไม่มีข้อมูล.",
|
||||
"message.no-websites-configured": "คุณยังไม่ได้ตั้งค่าเว็บไซต์ใด ๆ ไว้.",
|
||||
"message.page-not-found": "ไม่พบหน้านี้.",
|
||||
"message.powered-by": "ขับเคลื่อนโดย {name}",
|
||||
"message.reset-warning": "สถิติทั้งหมดสำหรับเว็บไซต์นี้จะถูกลบออก แต่โค้ดสำหรับใช้ติดตามของคุณจะยังคงอยู่เหมือนเดิม.",
|
||||
"message.save-success": "บันทึกข้อมูลเรียบร้อย.",
|
||||
"message.share-url": "นี่คือลิงก์ที่แชร์แบบสาธารณะสำหรับ {target}.",
|
||||
"message.toggle-charts": "เปิด/ปิดแผนภูมิ",
|
||||
"message.track-stats": "หากต้องการติดตามสถิติสำหรับ {target} ให้วางโค้ดต่อไปนี้ในส่วน {head} ของเว็บไซต์ของคุณ.",
|
||||
"message.type-delete": "พิมพ์ข้อความ {delete} ในช่องด้านล่างเพื่อยืนยัน.",
|
||||
"message.type-reset": "พิมพ์ข้อความ {reset} ในช่องด้านล่างเพื่อยืนยัน.",
|
||||
"metrics.actions": "การกระทำ",
|
||||
"metrics.average-visit-time": "ระยะเวลาเข้าชมเฉลี่ย",
|
||||
"metrics.bounce-rate": "อัตราตีกลับ",
|
||||
"metrics.browsers": "เบราว์เซอร์",
|
||||
"metrics.countries": "ประเทศ",
|
||||
"metrics.device.desktop": "เดสก์ท็อป",
|
||||
"metrics.device.laptop": "แล็ปท็อป",
|
||||
"metrics.device.mobile": "โทรศัพท์มือถือ",
|
||||
"metrics.device.tablet": "แท็บเล็ต",
|
||||
"metrics.devices": "อุปกรณ์",
|
||||
"metrics.events": "เหตุการณ์",
|
||||
"metrics.filter.combined": "ข้อมูลรวม",
|
||||
"metrics.filter.raw": "ข้อมูลดิบ",
|
||||
"metrics.languages": "ภาษา",
|
||||
"metrics.operating-systems": "ระบบปฏิบัติการ",
|
||||
"metrics.page-views": "การเข้าชม",
|
||||
"metrics.pages": "หน้าเพจ",
|
||||
"metrics.query-parameters": "Query parameters",
|
||||
"metrics.referrers": "แหล่งที่มา",
|
||||
"metrics.screens": "ขนาดหน้าจอ",
|
||||
"metrics.unique-visitors": "ผู้เข้าชม",
|
||||
"metrics.views": "การเข้าชม",
|
||||
"metrics.visitors": "ผู้เข้าชม"
|
||||
}
|
@ -4,7 +4,6 @@
|
||||
"label.add-website": "Web sitesi ekle",
|
||||
"label.administrator": "Yönetici",
|
||||
"label.all": "Tümü",
|
||||
"label.all-events": "All events",
|
||||
"label.all-time": "All time",
|
||||
"label.all-websites": "Tüm web siteleri",
|
||||
"label.back": "Geri",
|
||||
@ -68,6 +67,7 @@
|
||||
"message.confirm-reset": "Are your sure you want to reset {target}'s statistics?",
|
||||
"message.copied": "Panoya kopyalandı!",
|
||||
"message.delete-warning": "İlişkili tüm veriler de silinecektir.",
|
||||
"message.edit-dashboard": "Edit dashboard",
|
||||
"message.failure": "Bir şeyler ters gitti!",
|
||||
"message.get-share-url": "Paylaşım adresini al",
|
||||
"message.get-tracking-code": "İzleme kodunu al",
|
||||
@ -103,15 +103,10 @@
|
||||
"metrics.operating-systems": "İşletim sistemi",
|
||||
"metrics.page-views": "Sayfa görünümü",
|
||||
"metrics.pages": "Sayfalar",
|
||||
"metrics.query-parameters": "Query parameters",
|
||||
"metrics.referrers": "Yönlendirenler",
|
||||
"metrics.screens": "Ekranlar",
|
||||
"metrics.unique-visitors": "Tekil kullanıcı",
|
||||
"metrics.utm": "UTM",
|
||||
"metrics.utm_campaign": "UTM Campaign",
|
||||
"metrics.utm_content": "UTM Content",
|
||||
"metrics.utm_medium": "UTM Medium",
|
||||
"metrics.utm_source": "UTM Source",
|
||||
"metrics.utm_term": "UTM Term",
|
||||
"metrics.views": "Görüntüleme",
|
||||
"metrics.visitors": "Ziyaretçi"
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
"label.add-website": "Додати сайт",
|
||||
"label.administrator": "Адміністратор",
|
||||
"label.all": "Всі",
|
||||
"label.all-events": "Всі події",
|
||||
"label.all-time": "Весь час",
|
||||
"label.all-websites": "Всі сайти",
|
||||
"label.back": "Назад",
|
||||
@ -68,6 +67,7 @@
|
||||
"message.confirm-reset": "Ви впевнені, що бажаєте скинути статистику для {target}?",
|
||||
"message.copied": "Скопійовано!",
|
||||
"message.delete-warning": "Усі пов'язані дані будуть видалені також.",
|
||||
"message.edit-dashboard": "Edit dashboard",
|
||||
"message.failure": "Щось пішло не так.",
|
||||
"message.get-share-url": "Отримати публічне посилання",
|
||||
"message.get-tracking-code": "Отримати код для відслідковування",
|
||||
@ -103,15 +103,10 @@
|
||||
"metrics.operating-systems": "Операційні системи",
|
||||
"metrics.page-views": "Перегляди сторінок",
|
||||
"metrics.pages": "Сторінки",
|
||||
"metrics.query-parameters": "Query parameters",
|
||||
"metrics.referrers": "Джерела",
|
||||
"metrics.screens": "Screens",
|
||||
"metrics.unique-visitors": "Унікальні відвідувачі",
|
||||
"metrics.utm": "UTM",
|
||||
"metrics.utm_campaign": "UTM Campaign",
|
||||
"metrics.utm_content": "UTM Content",
|
||||
"metrics.utm_medium": "UTM Medium",
|
||||
"metrics.utm_source": "UTM Source",
|
||||
"metrics.utm_term": "UTM Term",
|
||||
"metrics.views": "Перегляди",
|
||||
"metrics.visitors": "Відвідувачі"
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
"label.add-website": "ویب سائٹ کا اضافہ کریں",
|
||||
"label.administrator": "منتظم",
|
||||
"label.all": "تمام",
|
||||
"label.all-events": "تمام واقعات",
|
||||
"label.all-time": "تمام وقت",
|
||||
"label.all-websites": "تمام ویب سائٹس",
|
||||
"label.back": "پیچھے",
|
||||
@ -68,6 +67,7 @@
|
||||
"message.confirm-reset": "کیا آپ واقعی {target} کے اعدادوشمار کو دوبارہ ترتیب دینا چاہتے ہیں؟",
|
||||
"message.copied": "کاپی کیا گیا!",
|
||||
"message.delete-warning": "تمام متعلقہ ڈیٹا بھی حذف کر دیا جائے گا۔",
|
||||
"message.edit-dashboard": "Edit dashboard",
|
||||
"message.failure": "کچھ غلط ہو گیا.",
|
||||
"message.get-share-url": "شیئر URL حاصل کریں",
|
||||
"message.get-tracking-code": "ٹریکنگ کوڈ حاصل کریں",
|
||||
@ -103,15 +103,10 @@
|
||||
"metrics.operating-systems": "آپریٹنگ سسٹمز",
|
||||
"metrics.page-views": "صفحہ کے نظارے",
|
||||
"metrics.pages": "صفحات",
|
||||
"metrics.query-parameters": "Query parameters",
|
||||
"metrics.referrers": "بھیجنے والے",
|
||||
"metrics.screens": "Screens",
|
||||
"metrics.unique-visitors": "منفرد زائرین",
|
||||
"metrics.utm": "UTM",
|
||||
"metrics.utm_campaign": "UTM Campaign",
|
||||
"metrics.utm_content": "UTM Content",
|
||||
"metrics.utm_medium": "UTM Medium",
|
||||
"metrics.utm_source": "UTM Source",
|
||||
"metrics.utm_term": "UTM Term",
|
||||
"metrics.views": "مناظر",
|
||||
"metrics.visitors": "زائرین"
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
"label.add-website": "Thêm website",
|
||||
"label.administrator": "Quản trị",
|
||||
"label.all": "Tất cả",
|
||||
"label.all-events": "Tất cả sự kiện",
|
||||
"label.all-time": "Toàn thời gian",
|
||||
"label.all-websites": "Tất cả website",
|
||||
"label.back": "Quay về",
|
||||
@ -68,6 +67,7 @@
|
||||
"message.confirm-reset": "Bạn có chắc chắn muốn tái thiết lập thống kê {target}?",
|
||||
"message.copied": "Đã sao chép!",
|
||||
"message.delete-warning": "Tất cả các dữ liệu liên quan cũng sẽ bị xoá.",
|
||||
"message.edit-dashboard": "Edit dashboard",
|
||||
"message.failure": "Đã xảy ra lỗi.",
|
||||
"message.get-share-url": "Lấy URL chia sẻ",
|
||||
"message.get-tracking-code": "Lấy mã theo dõi",
|
||||
@ -103,15 +103,10 @@
|
||||
"metrics.operating-systems": "Hệ điều hành",
|
||||
"metrics.page-views": "Lượt xem",
|
||||
"metrics.pages": "Trang",
|
||||
"metrics.query-parameters": "Query parameters",
|
||||
"metrics.referrers": "Liên kết giới thiệu",
|
||||
"metrics.screens": "Screens",
|
||||
"metrics.unique-visitors": "Khách truy cập một lần",
|
||||
"metrics.utm": "UTM",
|
||||
"metrics.utm_campaign": "UTM Campaign",
|
||||
"metrics.utm_content": "UTM Content",
|
||||
"metrics.utm_medium": "UTM Medium",
|
||||
"metrics.utm_source": "UTM Source",
|
||||
"metrics.utm_term": "UTM Term",
|
||||
"metrics.views": "Xem",
|
||||
"metrics.visitors": "Khách"
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
"label.add-website": "添加网站",
|
||||
"label.administrator": "管理员",
|
||||
"label.all": "所有",
|
||||
"label.all-events": "所有事件",
|
||||
"label.all-time": "所有时间段",
|
||||
"label.all-websites": "全部网站",
|
||||
"label.back": "返回",
|
||||
@ -68,6 +67,7 @@
|
||||
"message.confirm-reset": "您确定要重置 {target} 的数据吗?",
|
||||
"message.copied": "复制成功!",
|
||||
"message.delete-warning": "所有相关数据将会被删除。",
|
||||
"message.edit-dashboard": "Edit dashboard",
|
||||
"message.failure": "出现错误。",
|
||||
"message.get-share-url": "获取共享链接",
|
||||
"message.get-tracking-code": "获取跟踪代码",
|
||||
@ -103,15 +103,10 @@
|
||||
"metrics.operating-systems": "操作系统",
|
||||
"metrics.page-views": "页面浏览量",
|
||||
"metrics.pages": "网页",
|
||||
"metrics.query-parameters": "Query parameters",
|
||||
"metrics.referrers": "来源域名",
|
||||
"metrics.screens": "屏幕尺寸",
|
||||
"metrics.unique-visitors": "独立访客",
|
||||
"metrics.utm": "流量渠道标记(UTM)",
|
||||
"metrics.utm_campaign": "流量标识",
|
||||
"metrics.utm_content": "搜索关键字",
|
||||
"metrics.utm_medium": "流量来源类型",
|
||||
"metrics.utm_source": "流量来源",
|
||||
"metrics.utm_term": "流量搜索关键字",
|
||||
"metrics.views": "浏览量",
|
||||
"metrics.visitors": "访客"
|
||||
}
|
||||
|
@ -4,7 +4,6 @@
|
||||
"label.add-website": "增加網站",
|
||||
"label.administrator": "管理員",
|
||||
"label.all": "所有",
|
||||
"label.all-events": "所有事件",
|
||||
"label.all-time": "所有時間段",
|
||||
"label.all-websites": "全部網站",
|
||||
"label.back": "返回",
|
||||
@ -37,8 +36,8 @@
|
||||
"label.more": "更多",
|
||||
"label.name": "名字",
|
||||
"label.new-password": "新密碼",
|
||||
"label.none": "None",
|
||||
"label.owner": "Owner",
|
||||
"label.none": "無",
|
||||
"label.owner": "擁有者",
|
||||
"label.password": "密碼",
|
||||
"label.passwords-dont-match": "密碼不一致",
|
||||
"label.profile": "個人資料",
|
||||
@ -52,7 +51,7 @@
|
||||
"label.settings": "設置",
|
||||
"label.share-url": "分享連結",
|
||||
"label.single-day": "單日",
|
||||
"label.theme": "Theme",
|
||||
"label.theme": "主題",
|
||||
"label.this-month": "本月",
|
||||
"label.this-week": "本週",
|
||||
"label.this-year": "今年",
|
||||
@ -68,6 +67,7 @@
|
||||
"message.confirm-reset": "您確定要重置 {target} 的數據嗎?",
|
||||
"message.copied": "複製成功!",
|
||||
"message.delete-warning": "所有相關數據將會被刪除。",
|
||||
"message.edit-dashboard": "Edit dashboard",
|
||||
"message.failure": "出現錯誤。",
|
||||
"message.get-share-url": "獲得分享連結",
|
||||
"message.get-tracking-code": "獲得追蹤代碼",
|
||||
@ -82,7 +82,7 @@
|
||||
"message.reset-warning": "本網站的所有統計數據將被刪除,但您的跟蹤代碼將保持不變。",
|
||||
"message.save-success": "成功保存。",
|
||||
"message.share-url": "這是 {target} 的分享連結。",
|
||||
"message.toggle-charts": "Toggle charts",
|
||||
"message.toggle-charts": "切換圖表",
|
||||
"message.track-stats": "將以下代碼放入被設定網站的 {head} 部分來收集 {target} 的資料。",
|
||||
"message.type-delete": "在下方空格輸入 {delete} 確認删除",
|
||||
"message.type-reset": "在下方空格輸入 {reset} 確認删除",
|
||||
@ -99,19 +99,14 @@
|
||||
"metrics.events": "行為類別",
|
||||
"metrics.filter.combined": "總和",
|
||||
"metrics.filter.raw": "原始",
|
||||
"metrics.languages": "Languages",
|
||||
"metrics.operating-systems": "操作系统",
|
||||
"metrics.languages": "語言",
|
||||
"metrics.operating-systems": "操作系統",
|
||||
"metrics.page-views": "網頁流量",
|
||||
"metrics.pages": "網頁",
|
||||
"metrics.query-parameters": "Query parameters",
|
||||
"metrics.referrers": "指入域名",
|
||||
"metrics.screens": "Screens",
|
||||
"metrics.screens": "屏幕尺寸",
|
||||
"metrics.unique-visitors": "獨立訪客",
|
||||
"metrics.utm": "UTM",
|
||||
"metrics.utm_campaign": "UTM Campaign",
|
||||
"metrics.utm_content": "UTM Content",
|
||||
"metrics.utm_medium": "UTM Medium",
|
||||
"metrics.utm_source": "UTM Source",
|
||||
"metrics.utm_term": "UTM Term",
|
||||
"metrics.views": "頁面流量",
|
||||
"metrics.visitors": "獨立訪客"
|
||||
}
|
||||
|
@ -9,3 +9,10 @@ export function chunk(arr, size) {
|
||||
|
||||
return chunks;
|
||||
}
|
||||
|
||||
export function sortArrayByMap(arr, map = [], key) {
|
||||
if (!arr) return [];
|
||||
if (map.length === 0) return arr;
|
||||
|
||||
return map.map(id => arr.find(item => item[key] === id));
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
export const CURRENT_VERSION = process.env.currentVersion;
|
||||
export const AUTH_TOKEN = 'umami.auth';
|
||||
export const LOCALE_CONFIG = 'umami.locale';
|
||||
export const TIMEZONE_CONFIG = 'umami.timezone';
|
||||
@ -9,6 +10,7 @@ export const SHARE_TOKEN_HEADER = 'x-umami-share-token';
|
||||
export const HOMEPAGE_URL = 'https://umami.is';
|
||||
export const REPO_URL = 'https://github.com/umami-software/umami';
|
||||
export const UPDATES_URL = 'https://api.umami.is/v1/updates';
|
||||
export const TELEMETRY_PIXEL = 'https://i.umami.is/a.png';
|
||||
|
||||
export const DEFAULT_LOCALE = 'en-US';
|
||||
export const DEFAULT_THEME = 'light';
|
||||
|
31
lib/db.js
31
lib/db.js
@ -168,7 +168,6 @@ export function getFilterQuery(table, column, filters = {}, params = []) {
|
||||
if (table === 'pageview' || table === 'event') {
|
||||
arr.push(`and ${table}.${key}=$${params.length + 1}`);
|
||||
params.push(decodeURIComponent(filter));
|
||||
console.log(params);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -182,7 +181,7 @@ export function getFilterQuery(table, column, filters = {}, params = []) {
|
||||
}
|
||||
break;
|
||||
|
||||
case 'event_type':
|
||||
case 'event_name':
|
||||
if (table === 'event') {
|
||||
arr.push(`and ${table}.${key}=$${params.length + 1}`);
|
||||
params.push(decodeURIComponent(filter));
|
||||
@ -203,6 +202,11 @@ export function getFilterQuery(table, column, filters = {}, params = []) {
|
||||
params.push(`%://${filter}/%`);
|
||||
}
|
||||
break;
|
||||
|
||||
case 'query':
|
||||
if (table === 'pageview') {
|
||||
arr.push(`and ${table}.url like '%?%'`);
|
||||
}
|
||||
}
|
||||
|
||||
return arr;
|
||||
@ -212,17 +216,20 @@ export function getFilterQuery(table, column, filters = {}, params = []) {
|
||||
}
|
||||
|
||||
export function parseFilters(table, column, filters = {}, params = [], sessionKey = 'session_id') {
|
||||
const { domain, url, event_url, referrer, os, browser, device, country, event_type } = filters;
|
||||
const { domain, url, event_url, referrer, os, browser, device, country, event_name, query } =
|
||||
filters;
|
||||
|
||||
const pageviewFilters = { domain, url, referrer };
|
||||
console.log({ table, column, filters, params });
|
||||
|
||||
const pageviewFilters = { domain, url, referrer, query };
|
||||
const sessionFilters = { os, browser, device, country };
|
||||
const eventFilters = { url: event_url, event_type };
|
||||
const eventFilters = { url: event_url, event_name };
|
||||
|
||||
return {
|
||||
pageviewFilters,
|
||||
sessionFilters,
|
||||
eventFilters,
|
||||
event: { event_type },
|
||||
event: { event_name },
|
||||
joinSession:
|
||||
os || browser || device || country
|
||||
? `inner join session on ${table}.${sessionKey} = session.${sessionKey}`
|
||||
@ -277,14 +284,22 @@ export async function rawQueryClickhouse(query, params = [], debug = false) {
|
||||
return clickhouse.query(formattedQuery).toPromise();
|
||||
}
|
||||
|
||||
export async function findUnique(data) {
|
||||
if (data.length > 1) {
|
||||
throw `${data.length} records found when expecting 1.`;
|
||||
}
|
||||
|
||||
return data[0] ?? null;
|
||||
}
|
||||
|
||||
export async function runAnalyticsQuery(queries) {
|
||||
const db = getAnalyticsDatabase();
|
||||
|
||||
if (db === POSTGRESQL || db === MYSQL) {
|
||||
return queries[`${RELATIONAL}`]();
|
||||
return queries[RELATIONAL]();
|
||||
}
|
||||
|
||||
if (db === CLICKHOUSE) {
|
||||
return queries[`${CLICKHOUSE}`]();
|
||||
return queries[CLICKHOUSE]();
|
||||
}
|
||||
}
|
||||
|
@ -68,18 +68,37 @@ export const refFilter = data => {
|
||||
return Object.keys(map).map(key => ({ x: key, y: map[key], w: links[key] }));
|
||||
};
|
||||
|
||||
export const eventTypeFilter = (data, types) => {
|
||||
if (!types || types.length === 0) {
|
||||
return data;
|
||||
}
|
||||
|
||||
return data.filter(({ x }) => {
|
||||
const [event] = x.split('\t');
|
||||
return types.some(type => type === event);
|
||||
});
|
||||
};
|
||||
|
||||
export const percentFilter = data => {
|
||||
const total = data.reduce((n, { y }) => n + y, 0);
|
||||
return data.map(({ x, y, ...props }) => ({ x, y, z: total ? (y / total) * 100 : 0, ...props }));
|
||||
};
|
||||
|
||||
export const paramFilter = data => {
|
||||
const map = data.reduce((obj, { x, y }) => {
|
||||
try {
|
||||
const searchParams = new URLSearchParams(x.split('?')[1]);
|
||||
|
||||
for (const [key, value] of searchParams) {
|
||||
if (!obj[key]) {
|
||||
obj[key] = { [value]: y };
|
||||
} else if (!obj[key][value]) {
|
||||
obj[key][value] = y;
|
||||
} else {
|
||||
obj[key][value] += y;
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
// Ignore
|
||||
}
|
||||
|
||||
return obj;
|
||||
}, {});
|
||||
|
||||
const d = Object.keys(map).flatMap(key =>
|
||||
Object.keys(map[key]).map(n => ({ x: `${key}=${n}`, p: key, v: n, y: map[key][n] })),
|
||||
);
|
||||
|
||||
console.log({ map, d });
|
||||
|
||||
return d;
|
||||
};
|
||||
|
@ -1,5 +1,6 @@
|
||||
import {
|
||||
arSA,
|
||||
bn,
|
||||
cs,
|
||||
sk,
|
||||
da,
|
||||
@ -30,6 +31,7 @@ import {
|
||||
sl,
|
||||
sv,
|
||||
ta,
|
||||
th,
|
||||
tr,
|
||||
uk,
|
||||
zhCN,
|
||||
@ -41,6 +43,7 @@ import {
|
||||
|
||||
export const languages = {
|
||||
'ar-SA': { label: 'العربية', dateLocale: arSA, dir: 'rtl' },
|
||||
'bn-BD': { label: 'বাংলা', dateLocale: bn },
|
||||
'zh-CN': { label: '中文', dateLocale: zhCN },
|
||||
'zh-TW': { label: '中文(繁體)', dateLocale: zhTW },
|
||||
'ca-ES': { label: 'Català', dateLocale: ca },
|
||||
@ -77,6 +80,7 @@ export const languages = {
|
||||
'fi-FI': { label: 'Suomi', dateLocale: fi },
|
||||
'sv-SE': { label: 'Svenska', dateLocale: sv },
|
||||
'ta-IN': { label: 'தமிழ்', dateLocale: ta },
|
||||
'th-TH': { label: 'ภาษาไทย', dateLocale: th },
|
||||
'tr-TR': { label: 'Türkçe', dateLocale: tr },
|
||||
'uk-UA': { label: 'українська', dateLocale: uk },
|
||||
'ur-PK': { label: 'Urdu (Pakistan)', dateLocale: uk, dir: 'rtl' },
|
||||
|
@ -68,7 +68,7 @@ export async function getCountry(req, ip) {
|
||||
|
||||
// Database lookup
|
||||
if (!lookup) {
|
||||
lookup = await maxmind.open(path.resolve('./public/geo/GeoLite2-Country.mmdb'));
|
||||
lookup = await maxmind.open(path.resolve('node_modules/.geo/GeoLite2-Country.mmdb'));
|
||||
}
|
||||
|
||||
const result = lookup.get(ip);
|
||||
|
@ -37,8 +37,6 @@ export async function getSession(req) {
|
||||
|
||||
let session = await getSessionByUuid(session_uuid);
|
||||
|
||||
session = Array.isArray(session) && session[0] ? session[0] : session;
|
||||
|
||||
if (!session) {
|
||||
try {
|
||||
session = await createSession(website_id, {
|
||||
|
13
lib/web.js
13
lib/web.js
@ -61,10 +61,15 @@ export const setItem = (key, data, session) => {
|
||||
}
|
||||
};
|
||||
|
||||
export const getItem = (key, session) =>
|
||||
typeof window !== 'undefined'
|
||||
? JSON.parse((session ? sessionStorage : localStorage).getItem(key) || null)
|
||||
: null;
|
||||
export const getItem = (key, session) => {
|
||||
if (typeof window !== 'undefined') {
|
||||
const value = (session ? sessionStorage : localStorage).getItem(key);
|
||||
|
||||
if (value !== 'undefined') {
|
||||
return JSON.parse(value);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const removeItem = (key, session) => {
|
||||
if (typeof window !== 'undefined') {
|
||||
|
@ -33,14 +33,6 @@ function customScriptName(req) {
|
||||
}
|
||||
}
|
||||
|
||||
function forceSSL(req, res) {
|
||||
if (process.env.FORCE_SSL && req.nextUrl.protocol === 'http:') {
|
||||
res.headers.set('Strict-Transport-Security', 'max-age=31536000; includeSubDomains');
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
export default function middleware(req) {
|
||||
const fns = [customCollectEndpoint, customScriptName];
|
||||
|
||||
@ -51,5 +43,5 @@ export default function middleware(req) {
|
||||
}
|
||||
}
|
||||
|
||||
return forceSSL(req, NextResponse.next());
|
||||
return NextResponse.next();
|
||||
}
|
||||
|
@ -1,12 +1,41 @@
|
||||
require('dotenv').config();
|
||||
const pkg = require('./package.json');
|
||||
|
||||
const contentSecurityPolicy = `
|
||||
default-src 'self';
|
||||
img-src *;
|
||||
script-src 'self' 'unsafe-eval';
|
||||
style-src 'self' 'unsafe-inline';
|
||||
connect-src 'self' api.umami.is;
|
||||
frame-ancestors 'self';
|
||||
`;
|
||||
|
||||
const headers = [
|
||||
{
|
||||
key: 'X-DNS-Prefetch-Control',
|
||||
value: 'on',
|
||||
},
|
||||
{
|
||||
key: 'X-Frame-Options',
|
||||
value: 'SAMEORIGIN',
|
||||
},
|
||||
{
|
||||
key: 'Content-Security-Policy',
|
||||
value: contentSecurityPolicy.replace(/\s{2,}/g, ' ').trim(),
|
||||
},
|
||||
];
|
||||
|
||||
if (process.env.FORCE_SSL) {
|
||||
headers.push({
|
||||
key: 'Strict-Transport-Security',
|
||||
value: 'max-age=63072000; includeSubDomains; preload',
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
env: {
|
||||
currentVersion: pkg.version,
|
||||
loginDisabled: process.env.DISABLE_LOGIN,
|
||||
updatesDisabled: process.env.DISABLE_UPDATES,
|
||||
telemetryDisabled: process.env.DISABLE_TELEMETRY,
|
||||
isProduction: process.env.NODE_ENV === 'production',
|
||||
},
|
||||
basePath: process.env.BASE_PATH,
|
||||
output: 'standalone',
|
||||
@ -25,13 +54,16 @@ module.exports = {
|
||||
async headers() {
|
||||
return [
|
||||
{
|
||||
source: `/(.*\\.js)`,
|
||||
headers: [
|
||||
{
|
||||
key: 'Cache-Control',
|
||||
value: 'public, max-age=2592000', // 30 days
|
||||
source: '/:path*',
|
||||
headers,
|
||||
},
|
||||
],
|
||||
];
|
||||
},
|
||||
async rewrites() {
|
||||
return [
|
||||
{
|
||||
source: '/telemetry.js',
|
||||
destination: '/api/scripts/telemetry',
|
||||
},
|
||||
];
|
||||
},
|
||||
|
21
package.json
21
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "umami",
|
||||
"version": "1.36.1",
|
||||
"version": "1.37.0",
|
||||
"description": "A simple, fast, privacy-focused alternative to Google Analytics.",
|
||||
"author": "Mike Cao <mike@mikecao.com>",
|
||||
"license": "MIT",
|
||||
@ -13,17 +13,18 @@
|
||||
"dev": "next dev",
|
||||
"build": "npm-run-all build-tracker build-geo build-db build-app",
|
||||
"start": "npm-run-all check-db start-next",
|
||||
"start-docker": "npm-run-all check-db start-server",
|
||||
"start-docker": "npm-run-all check-db update-tracker start-server",
|
||||
"start-env": "node scripts/start-env.js",
|
||||
"start-server": "node server.js",
|
||||
"start-next": "next start",
|
||||
"build-app": "next build",
|
||||
"build-tracker": "rollup -c rollup.tracker.config.js",
|
||||
"build-db": "npm-run-all copy-db-files build-db-client",
|
||||
"build-lang": "npm-run-all format-lang compile-lang",
|
||||
"build-lang": "npm-run-all format-lang compile-lang download-country-names download-language-names",
|
||||
"build-geo": "node scripts/build-geo.js",
|
||||
"build-db-schema": "prisma db pull",
|
||||
"build-db-client": "prisma generate",
|
||||
"update-tracker": "node scripts/update-tracker.js",
|
||||
"update-db": "prisma migrate deploy",
|
||||
"check-db": "node scripts/check-db.js",
|
||||
"copy-db-files": "node scripts/copy-db-files.js",
|
||||
@ -55,7 +56,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@fontsource/inter": "4.5.7",
|
||||
"@prisma/client": "4.1.0",
|
||||
"@prisma/client": "4.1.1",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"chalk": "^4.1.1",
|
||||
"chart.js": "^2.9.4",
|
||||
@ -80,11 +81,12 @@
|
||||
"jose": "2.0.5",
|
||||
"maxmind": "^4.3.6",
|
||||
"moment-timezone": "^0.5.33",
|
||||
"next": "^12.2.0",
|
||||
"next": "^12.2.4",
|
||||
"node-fetch": "^3.2.8",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"prop-types": "^15.7.2",
|
||||
"react": "^17.0.0",
|
||||
"react-beautiful-dnd": "^13.1.0",
|
||||
"react-dom": "^17.0.0",
|
||||
"react-intl": "^5.24.7",
|
||||
"react-simple-maps": "^2.3.0",
|
||||
@ -106,7 +108,7 @@
|
||||
"@svgr/webpack": "^6.2.1",
|
||||
"cross-env": "^7.0.3",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-config-next": "^12.2.0",
|
||||
"eslint-config-next": "^12.2.4",
|
||||
"eslint-config-prettier": "^8.5.0",
|
||||
"eslint-plugin-prettier": "^4.0.0",
|
||||
"extract-react-intl-messages": "^4.1.1",
|
||||
@ -118,7 +120,7 @@
|
||||
"postcss-preset-env": "7.4.3",
|
||||
"postcss-rtlcss": "^3.6.1",
|
||||
"prettier": "^2.6.2",
|
||||
"prisma": "4.1.0",
|
||||
"prisma": "4.1.1",
|
||||
"prompts": "2.4.2",
|
||||
"rollup": "^2.70.1",
|
||||
"rollup-plugin-terser": "^7.0.2",
|
||||
@ -127,5 +129,8 @@
|
||||
"stylelint-config-prettier": "^9.0.3",
|
||||
"stylelint-config-recommended": "^7.0.0",
|
||||
"tar": "^6.1.2"
|
||||
}
|
||||
},
|
||||
"cacheDirectories": [
|
||||
".next/cache"
|
||||
]
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
import React from 'react';
|
||||
import Head from 'next/head';
|
||||
import { useRouter } from 'next/router';
|
||||
import { IntlProvider } from 'react-intl';
|
||||
|
@ -65,7 +65,7 @@ export default async (req, res) => {
|
||||
|
||||
const { type, payload } = getJsonBody(req);
|
||||
|
||||
let { url, referrer, event_type, event_value } = payload;
|
||||
let { url, referrer, event_name, event_data } = payload;
|
||||
|
||||
if (process.env.REMOVE_TRAILING_SLASH) {
|
||||
url = removeTrailingSlash(url);
|
||||
@ -74,7 +74,7 @@ export default async (req, res) => {
|
||||
if (type === 'pageview') {
|
||||
await savePageView(website_id, { session_id, session_uuid, url, referrer });
|
||||
} else if (type === 'event') {
|
||||
await saveEvent(website_id, { session_id, session_uuid, url, event_type, event_value });
|
||||
await saveEvent(website_id, { session_id, session_uuid, url, event_name, event_data });
|
||||
} else {
|
||||
return badRequest(res);
|
||||
}
|
||||
|
14
pages/api/config.js
Normal file
14
pages/api/config.js
Normal file
@ -0,0 +1,14 @@
|
||||
import { ok, methodNotAllowed } from 'lib/response';
|
||||
|
||||
export default async (req, res) => {
|
||||
if (req.method === 'GET') {
|
||||
return ok(res, {
|
||||
basePath: process.env.BASE_PATH || '',
|
||||
trackerScriptName: process.env.TRACKER_SCRIPT_NAME,
|
||||
updatesDisabled: !!process.env.DISABLE_UPDATES,
|
||||
telemetryDisabled: !!process.env.DISABLE_TELEMETRY,
|
||||
});
|
||||
}
|
||||
|
||||
return methodNotAllowed(res);
|
||||
};
|
18
pages/api/scripts/telemetry.js
Normal file
18
pages/api/scripts/telemetry.js
Normal file
@ -0,0 +1,18 @@
|
||||
import { CURRENT_VERSION, TELEMETRY_PIXEL } from 'lib/constants';
|
||||
|
||||
export default function handler(req, res) {
|
||||
res.setHeader('content-type', 'text/javascript');
|
||||
|
||||
if (process.env.DISABLE_TELEMETRY) {
|
||||
return res.send('/* telemetry disabled */');
|
||||
}
|
||||
|
||||
const script = `
|
||||
(()=>{const i=document.createElement('img');
|
||||
i.setAttribute('src','${TELEMETRY_PIXEL}?v=${CURRENT_VERSION}');
|
||||
i.setAttribute('style','width:0;height:0;position:absolute;pointer-events:none;');
|
||||
document.body.appendChild(i);})();
|
||||
`;
|
||||
|
||||
return res.send(script.replace(/\s\s+/g, ''));
|
||||
}
|
@ -14,7 +14,7 @@ export default async (req, res) => {
|
||||
return unauthorized(res);
|
||||
}
|
||||
|
||||
const { id, start_at, end_at, unit, tz, url, event_type } = req.query;
|
||||
const { id, start_at, end_at, unit, tz, url, event_name } = req.query;
|
||||
|
||||
if (!moment.tz.zone(tz) || !unitTypes.includes(unit)) {
|
||||
return badRequest(res);
|
||||
@ -26,7 +26,7 @@ export default async (req, res) => {
|
||||
|
||||
const events = await getEventMetrics(websiteId, startDate, endDate, tz, unit, {
|
||||
url,
|
||||
event_type,
|
||||
event_name,
|
||||
});
|
||||
|
||||
return ok(res, events);
|
||||
|
@ -1,12 +1,11 @@
|
||||
import { getPageviewMetrics, getSessionMetrics, getWebsiteById, getPageviewParams } from 'queries';
|
||||
import { getPageviewMetrics, getSessionMetrics, getWebsiteById } from 'queries';
|
||||
import { ok, methodNotAllowed, unauthorized, badRequest } from 'lib/response';
|
||||
import { allowQuery } from 'lib/auth';
|
||||
import { useCors } from 'lib/middleware';
|
||||
import { FILTER_IGNORED } from 'lib/constants';
|
||||
|
||||
const sessionColumns = ['browser', 'os', 'device', 'screen', 'country', 'language'];
|
||||
const pageviewColumns = ['url', 'referrer'];
|
||||
const paramTypes = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_content', 'utm_term', 'ref'];
|
||||
const pageviewColumns = ['url', 'referrer', 'query'];
|
||||
|
||||
function getTable(type) {
|
||||
if (type === 'event') {
|
||||
@ -17,12 +16,19 @@ function getTable(type) {
|
||||
return 'session';
|
||||
}
|
||||
|
||||
if (pageviewColumns.includes(type)) {
|
||||
return 'pageview';
|
||||
}
|
||||
|
||||
throw new Error('Invalid type');
|
||||
}
|
||||
|
||||
function getColumn(type) {
|
||||
if (type === 'event') {
|
||||
return `concat(event_type, '\t', event_value)`;
|
||||
return 'event_name';
|
||||
}
|
||||
if (type === 'query') {
|
||||
return 'url';
|
||||
}
|
||||
return type;
|
||||
}
|
||||
@ -41,52 +47,6 @@ export default async (req, res) => {
|
||||
const startDate = new Date(+start_at);
|
||||
const endDate = new Date(+end_at);
|
||||
|
||||
if (paramTypes.includes(type)) {
|
||||
const column = 'url';
|
||||
const table = getTable(type);
|
||||
|
||||
let domain;
|
||||
if (type === 'referrer') {
|
||||
const website = await getWebsiteById(websiteId);
|
||||
|
||||
if (!website) {
|
||||
return badRequest(res);
|
||||
}
|
||||
|
||||
domain = website.domain;
|
||||
}
|
||||
|
||||
const filters = {
|
||||
domain,
|
||||
url: type !== 'url' && table !== 'event' ? url : undefined,
|
||||
referrer: type !== 'referrer' ? referrer : true,
|
||||
os: type !== 'os' ? os : undefined,
|
||||
browser: type !== 'browser' ? browser : undefined,
|
||||
device: type !== 'device' ? device : undefined,
|
||||
country: type !== 'country' ? country : undefined,
|
||||
event_url: type !== 'url' && table === 'event' ? url : undefined,
|
||||
};
|
||||
|
||||
let data = await getPageviewParams(
|
||||
type,
|
||||
websiteId,
|
||||
startDate,
|
||||
endDate,
|
||||
column,
|
||||
table,
|
||||
filters,
|
||||
);
|
||||
|
||||
let terms = {};
|
||||
new Set(data.map(i => i.param)).forEach(term => (terms[term] = null));
|
||||
for (let { param } of data) terms[param] += 1;
|
||||
|
||||
return ok(
|
||||
res,
|
||||
Object.keys(terms).map(i => ({ x: i, y: terms[i] })),
|
||||
);
|
||||
}
|
||||
|
||||
if (sessionColumns.includes(type)) {
|
||||
let data = await getSessionMetrics(websiteId, startDate, endDate, type, {
|
||||
os,
|
||||
@ -116,6 +76,7 @@ export default async (req, res) => {
|
||||
|
||||
if (pageviewColumns.includes(type) || type === 'event') {
|
||||
let domain;
|
||||
|
||||
if (type === 'referrer') {
|
||||
const website = await getWebsiteById(websiteId);
|
||||
|
||||
@ -137,6 +98,7 @@ export default async (req, res) => {
|
||||
device: type !== 'device' ? device : undefined,
|
||||
country: type !== 'country' ? country : undefined,
|
||||
event_url: type !== 'url' && table === 'event' ? url : undefined,
|
||||
query: type === 'query' && table !== 'event' ? true : undefined,
|
||||
};
|
||||
|
||||
const data = await getPageviewMetrics(websiteId, startDate, endDate, column, table, filters);
|
||||
|
@ -2,11 +2,13 @@ import React from 'react';
|
||||
import Layout from 'components/layout/Layout';
|
||||
import TestConsole from 'components/pages/TestConsole';
|
||||
import useRequireLogin from 'hooks/useRequireLogin';
|
||||
import useUser from 'hooks/useUser';
|
||||
|
||||
export default function TestPage() {
|
||||
export default function ConsolePage({ enabled }) {
|
||||
const { loading } = useRequireLogin();
|
||||
const { user } = useUser();
|
||||
|
||||
if (loading) {
|
||||
if (loading || !enabled || !user?.is_admin) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -16,3 +18,9 @@ export default function TestPage() {
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
||||
export async function getServerSideProps() {
|
||||
return {
|
||||
props: { enabled: !!process.env.ENABLE_TEST_CONSOLE },
|
||||
};
|
||||
}
|
@ -2,8 +2,8 @@ import React from 'react';
|
||||
import Layout from 'components/layout/Layout';
|
||||
import LoginForm from 'components/forms/LoginForm';
|
||||
|
||||
export default function LoginPage() {
|
||||
if (process.env.loginDisabled) {
|
||||
export default function LoginPage({ loginDisabled }) {
|
||||
if (loginDisabled) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -13,3 +13,9 @@ export default function LoginPage() {
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
|
||||
export async function getServerSideProps() {
|
||||
return {
|
||||
props: { loginDisabled: !!process.env.DISABLE_LOGIN },
|
||||
};
|
||||
}
|
||||
|
1
public/intl/country/bn-BD.json
Normal file
1
public/intl/country/bn-BD.json
Normal file
File diff suppressed because one or more lines are too long
1
public/intl/country/th-TH.json
Normal file
1
public/intl/country/th-TH.json
Normal file
File diff suppressed because one or more lines are too long
1
public/intl/language/bn-BD.json
Normal file
1
public/intl/language/bn-BD.json
Normal file
File diff suppressed because one or more lines are too long
1
public/intl/language/th-TH.json
Normal file
1
public/intl/language/th-TH.json
Normal file
File diff suppressed because one or more lines are too long
@ -29,12 +29,6 @@
|
||||
"value": "الكل"
|
||||
}
|
||||
],
|
||||
"label.all-events": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "كافة الأحداث"
|
||||
}
|
||||
],
|
||||
"label.all-time": [
|
||||
{
|
||||
"type": 0,
|
||||
@ -477,6 +471,12 @@
|
||||
"value": "كافة البيانات المرتبطة سيم حذفها ايضا."
|
||||
}
|
||||
],
|
||||
"message.edit-dashboard": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Edit dashboard"
|
||||
}
|
||||
],
|
||||
"message.failure": [
|
||||
{
|
||||
"type": 0,
|
||||
@ -767,6 +767,12 @@
|
||||
"value": "الصفحات"
|
||||
}
|
||||
],
|
||||
"metrics.query-parameters": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Query parameters"
|
||||
}
|
||||
],
|
||||
"metrics.referrers": [
|
||||
{
|
||||
"type": 0,
|
||||
@ -785,42 +791,6 @@
|
||||
"value": "زائرون فريدون"
|
||||
}
|
||||
],
|
||||
"metrics.utm": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "UTM"
|
||||
}
|
||||
],
|
||||
"metrics.utm_campaign": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "UTM Campaign"
|
||||
}
|
||||
],
|
||||
"metrics.utm_content": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "UTM Content"
|
||||
}
|
||||
],
|
||||
"metrics.utm_medium": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "UTM Medium"
|
||||
}
|
||||
],
|
||||
"metrics.utm_source": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "UTM Source"
|
||||
}
|
||||
],
|
||||
"metrics.utm_term": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "UTM Term"
|
||||
}
|
||||
],
|
||||
"metrics.views": [
|
||||
{
|
||||
"type": 0,
|
||||
|
802
public/intl/messages/bn-BD.json
Normal file
802
public/intl/messages/bn-BD.json
Normal file
@ -0,0 +1,802 @@
|
||||
{
|
||||
"label.accounts": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "অ্যাকাউন্ট"
|
||||
}
|
||||
],
|
||||
"label.add-account": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "অ্যাকাউন্ট যুক্ত করুন"
|
||||
}
|
||||
],
|
||||
"label.add-website": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "ওয়েবসাইট যুক্ত করুন"
|
||||
}
|
||||
],
|
||||
"label.administrator": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "অ্যাডমিন"
|
||||
}
|
||||
],
|
||||
"label.all": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "সবগুলো"
|
||||
}
|
||||
],
|
||||
"label.all-time": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "সব সময়"
|
||||
}
|
||||
],
|
||||
"label.all-websites": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "সবগুলো ওয়েবসাইট"
|
||||
}
|
||||
],
|
||||
"label.back": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "পেছনে"
|
||||
}
|
||||
],
|
||||
"label.cancel": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "বাতিল"
|
||||
}
|
||||
],
|
||||
"label.change-password": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "পাসওয়ার্ড পরিবর্তন করুন"
|
||||
}
|
||||
],
|
||||
"label.confirm-password": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "পাসওয়ার্ড নিশ্চিত করুন"
|
||||
}
|
||||
],
|
||||
"label.copy-to-clipboard": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "কপি করুন"
|
||||
}
|
||||
],
|
||||
"label.current-password": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "বর্তমান পাসওয়ার্ড"
|
||||
}
|
||||
],
|
||||
"label.custom-range": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "কাস্টম রেঞ্জ"
|
||||
}
|
||||
],
|
||||
"label.dashboard": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "ড্যাশবোর্ড"
|
||||
}
|
||||
],
|
||||
"label.date-range": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "তারিখের পরিসীমা"
|
||||
}
|
||||
],
|
||||
"label.default-date-range": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "ডিফল্ট তারিখের পরিসীমা"
|
||||
}
|
||||
],
|
||||
"label.delete": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "মুছে ফেলুন"
|
||||
}
|
||||
],
|
||||
"label.delete-account": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "অ্যাকাউন্ট মুছুন"
|
||||
}
|
||||
],
|
||||
"label.delete-website": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "ওয়েবসাইট মুছুন"
|
||||
}
|
||||
],
|
||||
"label.dismiss": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "বাতিল"
|
||||
}
|
||||
],
|
||||
"label.domain": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "ডোমেইন"
|
||||
}
|
||||
],
|
||||
"label.edit": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "সম্পাদনা করুন"
|
||||
}
|
||||
],
|
||||
"label.edit-account": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "অ্যাকাউন্ট সম্পাদনা করুন"
|
||||
}
|
||||
],
|
||||
"label.edit-website": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "ওয়েবসাইট সম্পাদনা করুন"
|
||||
}
|
||||
],
|
||||
"label.enable-share-url": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "শেয়ার ইউআরএল শেয়ার করুন"
|
||||
}
|
||||
],
|
||||
"label.invalid": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "ভুল"
|
||||
}
|
||||
],
|
||||
"label.invalid-domain": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "ভুল ডোমেন"
|
||||
}
|
||||
],
|
||||
"label.language": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "ভাষা"
|
||||
}
|
||||
],
|
||||
"label.last-days": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "শেষ "
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"value": "x"
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": " দিন"
|
||||
}
|
||||
],
|
||||
"label.last-hours": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "শেষ "
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"value": "x"
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": " ঘন্টা"
|
||||
}
|
||||
],
|
||||
"label.logged-in-as": [
|
||||
{
|
||||
"type": 1,
|
||||
"value": "username"
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": " অ্যাকাউন্টে লগ ইন"
|
||||
}
|
||||
],
|
||||
"label.login": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "লগিন"
|
||||
}
|
||||
],
|
||||
"label.logout": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "লগ আউট"
|
||||
}
|
||||
],
|
||||
"label.more": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "আরও"
|
||||
}
|
||||
],
|
||||
"label.name": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "নাম"
|
||||
}
|
||||
],
|
||||
"label.new-password": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "নতুন পাসওয়ার্ড"
|
||||
}
|
||||
],
|
||||
"label.none": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "কিছুই না"
|
||||
}
|
||||
],
|
||||
"label.owner": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "মালিক"
|
||||
}
|
||||
],
|
||||
"label.password": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "পাসওয়ার্ড"
|
||||
}
|
||||
],
|
||||
"label.passwords-dont-match": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "পাসওয়ার্ড মেলে না"
|
||||
}
|
||||
],
|
||||
"label.profile": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "প্রোফাইল"
|
||||
}
|
||||
],
|
||||
"label.realtime": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "সরাসরি"
|
||||
}
|
||||
],
|
||||
"label.realtime-logs": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "সরাসরি লগ"
|
||||
}
|
||||
],
|
||||
"label.refresh": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "রিফ্রেশ"
|
||||
}
|
||||
],
|
||||
"label.required": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "প্রয়োজনীয়"
|
||||
}
|
||||
],
|
||||
"label.reset": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "রিসেট"
|
||||
}
|
||||
],
|
||||
"label.reset-website": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "ওয়েবসাইট রিসেট করুন"
|
||||
}
|
||||
],
|
||||
"label.save": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "সংরক্ষণ"
|
||||
}
|
||||
],
|
||||
"label.settings": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "সেটিংস"
|
||||
}
|
||||
],
|
||||
"label.share-url": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "ইউআরএল শেয়ার করুন"
|
||||
}
|
||||
],
|
||||
"label.single-day": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "একদিন"
|
||||
}
|
||||
],
|
||||
"label.theme": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "থিম"
|
||||
}
|
||||
],
|
||||
"label.this-month": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "এই মাস"
|
||||
}
|
||||
],
|
||||
"label.this-week": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "এই সপ্তাহ"
|
||||
}
|
||||
],
|
||||
"label.this-year": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "এই বছর"
|
||||
}
|
||||
],
|
||||
"label.timezone": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "সময়স্থান"
|
||||
}
|
||||
],
|
||||
"label.today": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "আজ"
|
||||
}
|
||||
],
|
||||
"label.tracking-code": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "ট্র্যাকিং কোড"
|
||||
}
|
||||
],
|
||||
"label.unknown": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "অজানা"
|
||||
}
|
||||
],
|
||||
"label.username": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "ব্যবহারকারীর নাম"
|
||||
}
|
||||
],
|
||||
"label.view-details": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "বিস্তারিত দেখুন"
|
||||
}
|
||||
],
|
||||
"label.websites": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "সবগুলো ওয়েবসাইট"
|
||||
}
|
||||
],
|
||||
"message.active-users": [
|
||||
{
|
||||
"type": 1,
|
||||
"value": "x"
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": " বর্তমান "
|
||||
},
|
||||
{
|
||||
"offset": 0,
|
||||
"options": {
|
||||
"one": {
|
||||
"value": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "visitor"
|
||||
}
|
||||
]
|
||||
},
|
||||
"other": {
|
||||
"value": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "visitors"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"pluralType": "cardinal",
|
||||
"type": 6,
|
||||
"value": "x"
|
||||
}
|
||||
],
|
||||
"message.confirm-delete": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "আপনি কি নিশ্চিত যে আপনি "
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"value": "target"
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": " মুছতে চান?"
|
||||
}
|
||||
],
|
||||
"message.confirm-reset": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "আপনি কি নিশ্চিত যে আপনি "
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"value": "target"
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": " এর পরিসংখ্যান পুনরায় সেট করতে চান?"
|
||||
}
|
||||
],
|
||||
"message.copied": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "কপি হয়েছে"
|
||||
}
|
||||
],
|
||||
"message.delete-warning": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "সমস্ত সম্পর্কিত ডেটা পাশাপাশি মুছে ফেলা হবে।"
|
||||
}
|
||||
],
|
||||
"message.edit-dashboard": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Edit dashboard"
|
||||
}
|
||||
],
|
||||
"message.failure": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "কিছু ভুল হয়েছে।"
|
||||
}
|
||||
],
|
||||
"message.get-share-url": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "শেয়ার ইউআরএল"
|
||||
}
|
||||
],
|
||||
"message.get-tracking-code": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "ট্র্যাকিং কোড পান"
|
||||
}
|
||||
],
|
||||
"message.go-to-settings": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "সেটিংস এ যান"
|
||||
}
|
||||
],
|
||||
"message.incorrect-username-password": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "ভুল ব্যবহারকারীর নাম/পাসওয়ার্ড।"
|
||||
}
|
||||
],
|
||||
"message.log.visitor": [
|
||||
{
|
||||
"type": 1,
|
||||
"value": "country"
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": " থেকে একজন ভিসিটর "
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"value": "ব্রাউজার"
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": ", ব্যবহার করছেন "
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"value": "os"
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": " "
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"value": "device"
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": " এর মধ্যে।"
|
||||
}
|
||||
],
|
||||
"message.new-version-available": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "নতুন সংস্করণ "
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"value": "version"
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": " পাওয়া গিয়েছে।"
|
||||
}
|
||||
],
|
||||
"message.no-data-available": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "কোন তথ্য নেই।"
|
||||
}
|
||||
],
|
||||
"message.no-websites-configured": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "কোনও ওয়েবসাইট কনফিগার করা নেই।"
|
||||
}
|
||||
],
|
||||
"message.page-not-found": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "পৃষ্ঠা খুঁজে পাওয়া যায়নি।"
|
||||
}
|
||||
],
|
||||
"message.powered-by": [
|
||||
{
|
||||
"type": 1,
|
||||
"value": "name"
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": " দ্বারা চালিত"
|
||||
}
|
||||
],
|
||||
"message.reset-warning": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "এই ওয়েবসাইটের সমস্ত পরিসংখ্যান মুছে ফেলা হবে, তবে আপনার ট্র্যাকিং কোডটি অক্ষত থাকবে।"
|
||||
}
|
||||
],
|
||||
"message.save-success": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "সংরক্ষিত হয়েছে।"
|
||||
}
|
||||
],
|
||||
"message.share-url": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "এটি "
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"value": "target"
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": " এর জন্য প্রকাশ্যে শেয়ার করার ইউআরএল।"
|
||||
}
|
||||
],
|
||||
"message.toggle-charts": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "চার্ট পরিবর্তন করুন"
|
||||
}
|
||||
],
|
||||
"message.track-stats": [
|
||||
{
|
||||
"type": 1,
|
||||
"value": "target"
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": " এর জন্য পরিসংখ্যানগুলি ট্র্যাক করতে, আপনার ওয়েবসাইটের "
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"value": "head"
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": " বিভাগে নিম্নলিখিত কোডটি রাখুন।"
|
||||
}
|
||||
],
|
||||
"message.type-delete": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "নিশ্চিত করতে নীচের বাক্সে "
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"value": "delete"
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": " টাইপ করুন।"
|
||||
}
|
||||
],
|
||||
"message.type-reset": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "নিশ্চিত করতে নীচের বাক্সে "
|
||||
},
|
||||
{
|
||||
"type": 1,
|
||||
"value": "reset"
|
||||
},
|
||||
{
|
||||
"type": 0,
|
||||
"value": " টাইপ করুন।"
|
||||
}
|
||||
],
|
||||
"metrics.actions": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "অ্যাকশনস"
|
||||
}
|
||||
],
|
||||
"metrics.average-visit-time": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "গড় পরিদর্শনের সময়"
|
||||
}
|
||||
],
|
||||
"metrics.bounce-rate": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "বহিষ্কারের হার"
|
||||
}
|
||||
],
|
||||
"metrics.browsers": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "ব্রাউজার"
|
||||
}
|
||||
],
|
||||
"metrics.countries": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "দেশ"
|
||||
}
|
||||
],
|
||||
"metrics.device.desktop": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "ডেস্কটপ"
|
||||
}
|
||||
],
|
||||
"metrics.device.laptop": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "ল্যাপটপ"
|
||||
}
|
||||
],
|
||||
"metrics.device.mobile": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "মুঠোফোন"
|
||||
}
|
||||
],
|
||||
"metrics.device.tablet": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "ট্যাবলেট"
|
||||
}
|
||||
],
|
||||
"metrics.devices": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "ডিভাইস গুলো"
|
||||
}
|
||||
],
|
||||
"metrics.events": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "ঘটনা"
|
||||
}
|
||||
],
|
||||
"metrics.filter.combined": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "সম্মিলিত"
|
||||
}
|
||||
],
|
||||
"metrics.filter.raw": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "অপরিশোধিত"
|
||||
}
|
||||
],
|
||||
"metrics.languages": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "ভাষা"
|
||||
}
|
||||
],
|
||||
"metrics.operating-systems": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "অপারেটিং সিস্টেম গুলো"
|
||||
}
|
||||
],
|
||||
"metrics.page-views": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "পৃষ্ঠা পরিদর্শন গুলো"
|
||||
}
|
||||
],
|
||||
"metrics.pages": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "পৃষ্ঠাগুলি"
|
||||
}
|
||||
],
|
||||
"metrics.query-parameters": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Query parameters"
|
||||
}
|
||||
],
|
||||
"metrics.referrers": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "রেফারার্স"
|
||||
}
|
||||
],
|
||||
"metrics.screens": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "স্ক্রিনগুলি"
|
||||
}
|
||||
],
|
||||
"metrics.unique-visitors": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "অনন্য ভিজিটর"
|
||||
}
|
||||
],
|
||||
"metrics.views": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "ভিউস"
|
||||
}
|
||||
],
|
||||
"metrics.visitors": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "পরিদর্শনার্থী"
|
||||
}
|
||||
]
|
||||
}
|
@ -29,12 +29,6 @@
|
||||
"value": "Tots"
|
||||
}
|
||||
],
|
||||
"label.all-events": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Tots els esdeveniments"
|
||||
}
|
||||
],
|
||||
"label.all-time": [
|
||||
{
|
||||
"type": 0,
|
||||
@ -477,6 +471,12 @@
|
||||
"value": "També s'esborraran totes les dades relacionades."
|
||||
}
|
||||
],
|
||||
"message.edit-dashboard": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Edit dashboard"
|
||||
}
|
||||
],
|
||||
"message.failure": [
|
||||
{
|
||||
"type": 0,
|
||||
@ -767,6 +767,12 @@
|
||||
"value": "Pàgines"
|
||||
}
|
||||
],
|
||||
"metrics.query-parameters": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "Query parameters"
|
||||
}
|
||||
],
|
||||
"metrics.referrers": [
|
||||
{
|
||||
"type": 0,
|
||||
@ -785,42 +791,6 @@
|
||||
"value": "Visitants únics"
|
||||
}
|
||||
],
|
||||
"metrics.utm": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "UTM"
|
||||
}
|
||||
],
|
||||
"metrics.utm_campaign": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "UTM Campaign"
|
||||
}
|
||||
],
|
||||
"metrics.utm_content": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "UTM Content"
|
||||
}
|
||||
],
|
||||
"metrics.utm_medium": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "UTM Medium"
|
||||
}
|
||||
],
|
||||
"metrics.utm_source": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "UTM Source"
|
||||
}
|
||||
],
|
||||
"metrics.utm_term": [
|
||||
{
|
||||
"type": 0,
|
||||
"value": "UTM Term"
|
||||
}
|
||||
],
|
||||
"metrics.views": [
|
||||
{
|
||||
"type": 0,
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user