Navigation: Make sure topnav is translated (#56643)

* initial translation progress

* more nav translations

* add subtitle translations

* more specific gitignore path

* fix unit tests
This commit is contained in:
Ashley Harrison 2022-10-11 11:45:58 +01:00 committed by GitHub
parent 8a3294dcdf
commit 8348f486d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 979 additions and 249 deletions

1
.gitignore vendored
View File

@ -180,6 +180,7 @@ compilation-stats.json
# Auto-generated internationalization files
public/locales/_build/
public/locales/*/*.js
public/locales/*/grafana_old.json
deployment_tools_config.json

View File

@ -6,6 +6,8 @@ import { useStyles2 } from '@grafana/ui';
import { Page } from 'app/core/components/Page/Page';
import { useNavModel } from 'app/core/hooks/useNavModel';
import { getNavTitle, getNavSubTitle } from '../NavBar/navBarItem-translations';
import { NavLandingPageCard } from './NavLandingPageCard';
interface Props {
@ -27,8 +29,8 @@ export function NavLandingPage({ navId }: Props) {
{directChildren?.map((child) => (
<NavLandingPageCard
key={child.id}
description={child.subTitle}
text={child.text}
description={getNavSubTitle(child.id) ?? child.subTitle}
text={getNavTitle(child.id) ?? child.text}
url={child.url ?? ''}
/>
))}
@ -36,14 +38,14 @@ export function NavLandingPage({ navId }: Props) {
)}
{nestedChildren?.map((child) => (
<section key={child.id}>
<h2 className={styles.nestedTitle}>{child.text}</h2>
<div className={styles.nestedDescription}>{child.subTitle}</div>
<h2 className={styles.nestedTitle}>{getNavTitle(child.id) ?? child.text}</h2>
<div className={styles.nestedDescription}>{getNavSubTitle(child.id) ?? child.subTitle}</div>
<div className={styles.grid}>
{child.children?.map((child) => (
<NavLandingPageCard
key={child.id}
description={child.subTitle}
text={child.text}
description={getNavSubTitle(child.id) ?? child.subTitle}
text={getNavTitle(child.id) ?? child.text}
url={child.url ?? ''}
/>
))}

View File

@ -2,6 +2,7 @@ import React from 'react';
import { useToggle } from 'react-use';
import { Drawer, ToolbarButton } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { DEFAULT_FEED_URL } from 'app/plugins/panel/news/constants';
import { NewsWrapper } from './NewsWrapper';
@ -17,7 +18,7 @@ export function NewsContainer() {
<>
<ToolbarButton onClick={onChildClick} iconOnly icon="rss" aria-label="News" />
{showNewsDrawer && (
<Drawer title="Latest from the blog" scrollableContent onClose={onToggleShowNewsDrawer}>
<Drawer title={t('news.title', 'Latest from the blog')} scrollableContent onClose={onToggleShowNewsDrawer}>
<NewsWrapper feedUrl={DEFAULT_FEED_URL} />
</Drawer>
)}

View File

@ -6,7 +6,7 @@ import { useLocation } from 'react-router-dom';
import { GrafanaTheme2, NavModelItem } from '@grafana/data';
import { Menu, MenuItem, useStyles2 } from '@grafana/ui';
import getNavTranslation from '../../NavBar/navBarItem-translations';
import { getNavTitle } from '../../NavBar/navBarItem-translations';
import { enrichConfigItems, enrichWithInteractionTracking } from '../../NavBar/utils';
export interface TopNavBarMenuProps {
@ -27,13 +27,13 @@ export function TopNavBarMenu({ node: nodePlain }: TopNavBarMenuProps) {
<Menu
header={
<div onClick={(e) => e.stopPropagation()} className={styles.header}>
<div>{node.text}</div>
<div>{getNavTitle(node.id) ?? node.text}</div>
{node.subTitle && <div className={styles.subTitle}>{node.subTitle}</div>}
</div>
}
>
{node.children?.map((item) => {
const itemText = getNavTranslation(item.id) ?? item.text;
const itemText = getNavTitle(item.id) ?? item.text;
const showExternalLinkIcon = /^https?:\/\//.test(item.url || '');
return item.url ? (
<MenuItem

View File

@ -2,6 +2,7 @@ import React from 'react';
import { locationService } from '@grafana/runtime';
import { FilterInput } from '@grafana/ui';
import { t } from 'app/core/internationalization';
import { useSearchQuery } from 'app/features/search/hooks/useSearchQuery';
export function TopSearchBarInput() {
@ -20,7 +21,7 @@ export function TopSearchBarInput() {
return (
<FilterInput
onClick={onOpenSearch}
placeholder="Search Grafana"
placeholder={t('nav.search.placeholder', 'Search Grafana')}
value={query.query ?? ''}
onChange={onSearchChange}
/>

View File

@ -1,5 +1,7 @@
import { NavModelItem } from '@grafana/data';
import { getNavTitle } from '../NavBar/navBarItem-translations';
import { Breadcrumb } from './types';
export function buildBreadcrumbs(homeNav: NavModelItem, sectionNav: NavModelItem, pageNav?: NavModelItem) {
@ -16,10 +18,10 @@ export function buildBreadcrumbs(homeNav: NavModelItem, sectionNav: NavModelItem
}
if (!foundHome && !node.hideFromBreadcrumbs) {
if (urlToMatch === homeNav.url) {
crumbs.unshift({ text: homeNav.text, href: node.url ?? '' });
crumbs.unshift({ text: getNavTitle(homeNav.id) ?? homeNav.text, href: node.url ?? '' });
foundHome = true;
} else {
crumbs.unshift({ text: node.text, href: node.url ?? '' });
crumbs.unshift({ text: getNavTitle(node.id) ?? node.text, href: node.url ?? '' });
}
}

View File

@ -3,6 +3,7 @@ import React from 'react';
import { LinkTarget } from '@grafana/data';
import { config } from '@grafana/runtime';
import { Icon, IconName } from '@grafana/ui';
import { t } from 'app/core/internationalization';
export interface FooterLink {
target: LinkTarget;
@ -17,21 +18,21 @@ export let getFooterLinks = (): FooterLink[] => {
{
target: '_blank',
id: 'documentation',
text: 'Documentation',
text: t('nav.help/documentation', 'Documentation'),
icon: 'document-info',
url: 'https://grafana.com/docs/grafana/latest/?utm_source=grafana_footer',
},
{
target: '_blank',
id: 'support',
text: 'Support',
text: t('nav.help/support', 'Support'),
icon: 'question-circle',
url: 'https://grafana.com/products/enterprise/?utm_source=grafana_footer',
},
{
target: '_blank',
id: 'community',
text: 'Community',
text: t('nav.help/community', 'Community'),
icon: 'comments-alt',
url: 'https://community.grafana.com/?utm_source=grafana_footer',
},

View File

@ -4,7 +4,7 @@ import React from 'react';
import { GrafanaTheme2, NavModelItem } from '@grafana/data';
import { toIconName, useStyles2 } from '@grafana/ui';
import getNavTranslation from '../NavBar/navBarItem-translations';
import { getNavTitle } from '../NavBar/navBarItem-translations';
import { isMatchOrChildMatch } from '../NavBar/utils';
import { NavBarMenuItem } from './NavBarMenuItem';
@ -22,7 +22,7 @@ export function NavBarMenuItemWrapper({
const styles = useStyles2(getStyles);
if (link.emptyMessageId && !linkHasChildren(link)) {
const emptyMessageTranslated = getNavTranslation(link.emptyMessageId);
const emptyMessageTranslated = getNavTitle(link.emptyMessageId);
return (
<NavBarMenuSection link={link}>
<ul className={styles.children}>
@ -52,7 +52,7 @@ export function NavBarMenuItemWrapper({
target={childLink.target}
url={childLink.url}
>
{childLink.text}
{getNavTitle(childLink.id) ?? childLink.text}
</NavBarMenuItem>
)
);

View File

@ -6,6 +6,7 @@ import { Button, Icon, useStyles2 } from '@grafana/ui';
import { NavBarItemIcon } from '../NavBar/NavBarItemIcon';
import { NavFeatureHighlight } from '../NavBar/NavFeatureHighlight';
import { getNavTitle } from '../NavBar/navBarItem-translations';
import { hasChildMatch } from '../NavBar/utils';
import { NavBarMenuItem } from './NavBarMenuItem';
@ -50,7 +51,7 @@ export function NavBarMenuSection({
<FeatureHighlightWrapper>
<NavBarItemIcon link={link} />
</FeatureHighlightWrapper>
{link.text}
{getNavTitle(link.id) ?? link.text}
</div>
</NavBarMenuItem>
{Boolean(link.children?.length) && (

View File

@ -11,7 +11,7 @@ import { NavBarItemMenuTrigger } from './NavBarItemMenuTrigger';
import { getNavBarItemWithoutMenuStyles } from './NavBarItemWithoutMenu';
import { NavBarMenuItem } from './NavBarMenuItem';
import { useNavBarContext } from './context';
import getNavTranslation from './navBarItem-translations';
import { getNavTitle } from './navBarItem-translations';
import { getNavModelItemKey } from './utils';
export interface Props {
@ -53,7 +53,7 @@ const NavBarItem = ({ isActive = false, className, reverseMenuDirection = false,
}
};
const linkText = getNavTranslation(link.id) ?? link.text;
const linkText = getNavTitle(link.id) ?? link.text;
return (
<li className={cx(styles.container, { [styles.containerHover]: section.id === menuIdOpen }, className)}>
@ -72,7 +72,7 @@ const NavBarItem = ({ isActive = false, className, reverseMenuDirection = false,
onNavigate={onNavigate}
>
{(item: NavModelItem) => {
const itemText = getNavTranslation(item.id) ?? item.text;
const itemText = getNavTitle(item.id) ?? item.text;
const isSection = item.menuItemType === NavMenuItemType.Section;
const iconName = item.icon ? toIconName(item.icon) : undefined;
const icon = item.showIconInNavbar && !isSection ? iconName : undefined;

View File

@ -10,7 +10,7 @@ import { CustomScrollbar, useTheme2 } from '@grafana/ui';
import { NavBarItemMenuItem } from './NavBarItemMenuItem';
import { useNavBarItemMenuContext } from './context';
import getNavTranslation from './navBarItem-translations';
import { getNavTitle } from './navBarItem-translations';
import { getNavModelItemKey } from './utils';
export interface NavBarItemMenuProps extends SpectrumMenuProps<NavModelItem> {
@ -59,7 +59,7 @@ export function NavBarItemMenu(props: NavBarItemMenuProps): ReactElement | null
));
if (itemComponents.length === 0 && section.value.emptyMessageId) {
const emptyMessageTranslated = getNavTranslation(section.value.emptyMessageId);
const emptyMessageTranslated = getNavTitle(section.value.emptyMessageId);
itemComponents.push(
<div key="empty-message" className={styles.emptyMessage}>
{emptyMessageTranslated}

View File

@ -15,7 +15,7 @@ import { NavBarItemWithoutMenu } from './NavBarItemWithoutMenu';
import { NavBarMenuItem } from './NavBarMenuItem';
import { NavBarToggle } from './NavBarToggle';
import { NavFeatureHighlight } from './NavFeatureHighlight';
import getNavTranslation from './navBarItem-translations';
import { getNavTitle } from './navBarItem-translations';
import { isMatchOrChildMatch } from './utils';
const MENU_WIDTH = '350px';
@ -267,7 +267,7 @@ export function NavItem({
</CollapsibleNavItem>
);
} else if (link.emptyMessageId) {
const emptyMessageTranslated = getNavTranslation(link.emptyMessageId);
const emptyMessageTranslated = getNavTitle(link.emptyMessageId);
return (
<CollapsibleNavItem onClose={onClose} link={link} isActive={isMatchOrChildMatch(link, activeItem)}>
<ul className={styles.children}>

View File

@ -2,98 +2,194 @@
// Because the navigation content is dynamic (defined in the backend), we can not use
// the normal inline message definition method.
import { config } from '@grafana/runtime';
import { t } from 'app/core/internationalization';
// The keys of the TRANSLATED_MENU_ITEMS object (NOT the id inside the defineMessage function)
// must match the ID of the navigation item, as defined in the backend nav model
// see pkg/api/index.go
export default function getNavTranslation(navId: string | undefined) {
export function getNavTitle(navId: string | undefined) {
switch (navId) {
case 'home':
return t('nav.home', 'Home');
return t('nav.home.title', 'Home');
case 'create':
return t('nav.create', 'Create');
return t('nav.create.title', 'Create');
case 'create-dashboard':
return t('nav.create-dashboard', 'Dashboard');
return t('nav.create-dashboard.title', 'Dashboard');
case 'folder':
return t('nav.create-folder', 'Folder');
return t('nav.create-folder.title', 'Folder');
case 'import':
return t('nav.create-import', 'Import');
return t('nav.create-import.title', 'Import');
case 'alert':
return t('nav.create-alert', 'New alert rule');
return t('nav.create-alert.title', 'New alert rule');
case 'starred':
return t('nav.starred', 'Starred');
return t('nav.starred.title', 'Starred');
case 'starred-empty':
return t('nav.starred-empty', 'Your starred dashboards will appear here');
return t('nav.starred-empty.title', 'Your starred dashboards will appear here');
case 'dashboards':
return t('nav.dashboards', 'Dashboards');
return t('nav.dashboards.title', 'Dashboards');
case 'dashboards/browse':
return t('nav.manage-dashboards', 'Browse');
return config.featureToggles.topnav
? t('nav.dashboards.title', 'Dashboards')
: t('nav.manage-dashboards.title', 'Browse');
case 'dashboards/playlists':
return t('nav.playlists', 'Playlists');
return t('nav.playlists.title', 'Playlists');
case 'dashboards/snapshots':
return t('nav.snapshots', 'Snapshots');
return t('nav.snapshots.title', 'Snapshots');
case 'dashboards/library-panels':
return t('nav.library-panels', 'Library panels');
return t('nav.library-panels.title', 'Library panels');
case 'dashboards/new':
return t('nav.new-dashboard', 'New dashboard');
return t('nav.new-dashboard.title', 'New dashboard');
case 'dashboards/folder/new':
return t('nav.new-folder', 'New folder');
return t('nav.new-folder.title', 'New folder');
case 'scenes':
return t('nav.scenes.title', 'Scenes');
case 'explore':
return t('nav.explore', 'Explore');
return t('nav.explore.title', 'Explore');
case 'alerting':
return t('nav.alerting', 'Alerting');
return t('nav.alerting.title', 'Alerting');
case 'alerting-legacy':
return t('nav.alerting-legacy', 'Alerting (legacy)');
return t('nav.alerting-legacy.title', 'Alerting (legacy)');
case 'alert-list':
return t('nav.alerting-list', 'Alert rules');
return t('nav.alerting-list.title', 'Alert rules');
case 'receivers':
return t('nav.alerting-receivers', 'Contact points');
return t('nav.alerting-receivers.title', 'Contact points');
case 'am-routes':
return t('nav.alerting-am-routes', 'Notification policies');
return t('nav.alerting-am-routes.title', 'Notification policies');
case 'channels':
return t('nav.alerting-channels', 'Notification channels');
return t('nav.alerting-channels.title', 'Notification channels');
case 'silences':
return t('nav.alerting-silences', 'Silences');
return t('nav.alerting-silences.title', 'Silences');
case 'groups':
return t('nav.alerting-groups', 'Groups');
return t('nav.alerting-groups.title', 'Groups');
case 'alerting-admin':
return t('nav.alerting-admin', 'Admin');
return t('nav.alerting-admin.title', 'Admin');
case 'cfg':
return t('nav.config', 'Configuration');
return t('nav.config.title', 'Configuration');
case 'datasources':
return t('nav.datasources', 'Data sources');
return t('nav.datasources.title', 'Data sources');
case 'correlations':
return t('nav.correlations', 'Correlations');
return t('nav.correlations.title', 'Correlations');
case 'users':
return t('nav.users', 'Users');
return t('nav.users.title', 'Users');
case 'teams':
return t('nav.teams', 'Teams');
return t('nav.teams.title', 'Teams');
case 'plugins':
return t('nav.plugins', 'Plugins');
return t('nav.plugins.title', 'Plugins');
case 'org-settings':
return t('nav.org-settings', 'Preferences');
return t('nav.org-settings.title', 'Preferences');
case 'apikeys':
return t('nav.api-keys', 'API keys');
return t('nav.api-keys.title', 'API keys');
case 'serviceaccounts':
return t('nav.service-accounts', 'Service accounts');
return t('nav.service-accounts.title', 'Service accounts');
case 'admin':
return t('nav.admin.title', 'Server admin');
case 'global-users':
return t('nav.global-users.title', 'Users');
case 'global-orgs':
return t('nav.global-orgs.title', 'Organizations');
case 'server-settings':
return t('nav.server-settings.title', 'Settings');
case 'storage':
return t('nav.storage.title', 'Storage');
case 'upgrading':
return t('nav.upgrading.title', 'Stats and license');
case 'live':
return t('nav.live', 'Event streaming');
return t('nav.live.title', 'Event streaming');
case 'live-status':
return t('nav.live-status', 'Status');
return t('nav.live-status.title', 'Status');
case 'live-pipeline':
return t('nav.live-pipeline', 'Pipeline');
return t('nav.live-pipeline.title', 'Pipeline');
case 'live-cloud':
return t('nav.live-cloud', 'Cloud');
return t('nav.live-cloud.title', 'Cloud');
case 'monitoring':
return t('nav.monitoring.title', 'Monitoring');
case 'apps':
return t('nav.apps.title', 'Apps');
case 'alerts-and-incidents':
return t('nav.alerts-and-incidents.title', 'Alerts & incidents');
case 'help':
return t('nav.help', 'Help');
case 'profile-settings':
return t('nav.profile/settings', 'Preferences');
case 'change-password':
return t('nav.profile/password', 'Change password');
return t('nav.help.title', 'Help');
case 'profile/settings':
return t('nav.profile/settings.title', 'Preferences');
case 'profile/notifications':
return t('nav.profile/notifications.title', 'Notification history');
case 'profile/password':
return t('nav.profile/password.title', 'Change password');
case 'sign-out':
return t('nav.sign-out', 'Sign out');
return t('nav.sign-out.title', 'Sign out');
default:
return undefined;
}
}
export function getNavSubTitle(navId: string | undefined) {
switch (navId) {
case 'dashboards':
return t('nav.dashboards.subtitle', 'Create and manage dashboards to visualize your data');
case 'dashboards/browse':
return config.featureToggles.topnav
? t('nav.dashboards.subtitle', 'Create and manage dashboards to visualize your data')
: undefined;
case 'dashboards/playlists':
return t('nav.playlists.subtitle', 'Groups of dashboards that are displayed in a sequence');
case 'dashboards/snapshots':
return t(
'nav.snapshots.subtitle',
'Interactive, publically available, point-in-time representations of dashboards'
);
case 'dashboards/library-panels':
return t('nav.library-panels.subtitle', 'Reusable panels that can be added to multiple dashboards');
case 'alerting':
return t('nav.alerting.subtitle', 'Learn about problems in your systems moments after they occur');
case 'alert-list':
return t('nav.alerting-list.subtitle', 'Rules that determine whether an alert will fire');
case 'receivers':
return t('nav.alerting-receivers.subtitle', 'Decide how your contacts are notified when an alert fires');
case 'am-routes':
return t('nav.alerting-am-routes.subtitle', 'Determine how alerts are routed to contact points');
case 'silences':
return t('nav.alerting-silences.subtitle', 'Stop notifications from one or more alerting rules');
case 'groups':
return t('nav.alerting-groups.subtitle', 'See grouped alerts from an Alertmanager instance');
case 'datasources':
return t('nav.datasources.subtitle', 'Add and configure data sources');
case 'correlations':
return t('nav.correlations.subtitle', 'Add and configure correlations');
case 'users':
return t('nav.users.subtitle', 'Invite and assign roles to users');
case 'teams':
return t('nav.teams.subtitle', 'Groups of users that have common dashboard and permission needs');
case 'plugins':
return t('nav.plugins.subtitle', 'Extend the Grafana experience with plugins');
case 'org-settings':
return t('nav.org-settings.subtitle', 'Manage preferences across an organization');
case 'apikeys':
return t('nav.api-keys.subtitle', 'Manage and create API keys that are used to interact with Grafana HTTP APIs');
case 'serviceaccounts':
return t('nav.service-accounts.subtitle', 'Use service accounts to run automated workloads in Grafana');
case 'global-users':
return t('nav.global-users.subtitle', 'Manage and create users across the whole Grafana server');
case 'global-orgs':
return t('nav.global-orgs.subtitle', 'Isolated instances of Grafana running on the same server');
case 'server-settings':
return t('nav.server-settings.subtitle', 'View the settings defined in your Grafana config');
case 'storage':
return t('nav.storage.subtitle', 'Manage file storage');
case 'admin':
return config.featureToggles.topnav
? t(
'nav.admin.subtitle',
'Manage server-wide settings and access to resources such as organizations, users, and licenses'
)
: undefined;
case 'apps':
return t('nav.apps.subtitle', 'App plugins that extend the Grafana experience');
case 'monitoring':
return t('nav.monitoring.subtitle', 'Monitoring and infrastructure apps');
case 'alerts-and-incidents':
return t('nav.alerts-and-incidents.subtitle', 'Alerting and incident management apps');
default:
return undefined;
}

View File

@ -38,7 +38,7 @@ describe('enrichConfigItems', () => {
contextSrv.user.isSignedIn = false;
setContextSrv(contextSrv);
const enrichedConfigItems = enrichConfigItems(mockItems, mockLocation);
const signInNode = enrichedConfigItems.find((item) => item.id === 'signin');
const signInNode = enrichedConfigItems.find((item) => item.id === 'sign-in');
expect(signInNode).toBeDefined();
});
@ -47,7 +47,7 @@ describe('enrichConfigItems', () => {
contextSrv.user.isSignedIn = true;
setContextSrv(contextSrv);
const enrichedConfigItems = enrichConfigItems(mockItems, mockLocation);
const signInNode = enrichedConfigItems.find((item) => item.id === 'signin');
const signInNode = enrichedConfigItems.find((item) => item.id === 'sign-in');
expect(signInNode).toBeDefined();
});

View File

@ -2,6 +2,7 @@ import { Location } from 'history';
import { locationUtil, NavModelItem, NavSection } from '@grafana/data';
import { config, reportInteraction } from '@grafana/runtime';
import { t } from 'app/core/internationalization';
import { contextSrv } from 'app/core/services/context_srv';
import { ShowModalReactEvent } from '../../../types/events';
@ -38,10 +39,10 @@ export const enrichConfigItems = (items: NavModelItem[], location: Location<unkn
items.unshift({
icon: 'signout',
id: 'signin',
id: 'sign-in',
section: NavSection.Config,
target: '_self',
text: 'Sign in',
text: t('nav.sign-in', 'Sign in'),
url: loginUrl,
});
}
@ -54,7 +55,7 @@ export const enrichConfigItems = (items: NavModelItem[], location: Location<unkn
...getFooterLinks(),
{
id: 'keyboard-shortcuts',
text: 'Keyboard shortcuts',
text: t('nav.help/keyboard-shortcuts', 'Keyboard shortcuts'),
icon: 'keyboard',
onClick: onOpenShortcuts,
},
@ -66,7 +67,7 @@ export const enrichConfigItems = (items: NavModelItem[], location: Location<unkn
...menuItems,
{
id: 'switch-organization',
text: 'Switch organization',
text: t('nav.profile/switch-org', 'Switch organization'),
icon: 'arrow-random',
onClick: onOpenOrgSwitcher,
},

View File

@ -4,6 +4,8 @@ import React from 'react';
import { NavModelItem, GrafanaTheme2 } from '@grafana/data';
import { useStyles2 } from '@grafana/ui';
import { getNavSubTitle, getNavTitle } from '../NavBar/navBarItem-translations';
export interface Props {
navItem: NavModelItem;
subTitle?: React.ReactNode;
@ -11,13 +13,13 @@ export interface Props {
export function PageHeader({ navItem, subTitle }: Props) {
const styles = useStyles2(getStyles);
const sub = subTitle ?? navItem.subTitle;
const sub = subTitle ?? getNavSubTitle(navItem.id) ?? navItem.subTitle;
return (
<>
<h1 className={styles.pageTitle}>
{navItem.img && <img className={styles.pageImg} src={navItem.img} alt={`logo for ${navItem.text}`} />}
{navItem.text}
{getNavTitle(navItem.id) ?? navItem.text}
</h1>
{sub && <div className={styles.pageSubTitle}>{sub}</div>}
{navItem.headerExtra && <navItem.headerExtra />}

View File

@ -6,6 +6,8 @@ import { selectors } from '@grafana/e2e-selectors';
import { useStyles2, Icon } from '@grafana/ui';
import { HOME_NAV_ID } from 'app/core/reducers/navModel';
import { getNavTitle } from '../NavBar/navBarItem-translations';
export interface Props {
item: NavModelItem;
}
@ -40,7 +42,7 @@ export function SectionNavItem({ item }: Props) {
>
{isSectionRoot && item.icon && <Icon name={item.icon} />}
{isSectionRoot && item.img && <img className={styles.sectionImg} src={item.img} alt={`logo of ${item.text}`} />}
{item.text}
{getNavTitle(item.id) ?? item.text}
{item.tabSuffix && <item.tabSuffix className={styles.suffix} />}
</a>
{children?.map((child, index) => (

View File

@ -103,54 +103,209 @@
}
},
"nav": {
"alerting": "Alerting",
"alerting-admin": "Admin",
"alerting-am-routes": "Notification policies",
"alerting-channels": "Notification channels",
"alerting-groups": "Groups",
"alerting-legacy": "Alerting (legacy)",
"alerting-list": "Alert rules",
"alerting-receivers": "Contact points",
"alerting-silences": "Silences",
"api-keys": "API keys",
"config": "Configuration",
"correlations": "Correlations",
"create": "Create",
"create-alert": "New alert rule",
"create-dashboard": "Dashboard",
"create-folder": "Folder",
"create-import": "Import",
"dashboards": "Dashboards",
"datasources": "Data sources",
"explore": "Explore",
"help": "Help",
"home": "Home",
"library-panels": "Library panels",
"live": "Event streaming",
"live-cloud": "Cloud",
"live-pipeline": "Pipeline",
"live-status": "Status",
"manage-dashboards": "Browse",
"new-dashboard": "New dashboard",
"new-folder": "New folder",
"org-settings": "Preferences",
"playlists": "Playlists",
"plugins": "Plugins",
"profile/password": "Change password",
"profile/settings": "Preferences",
"service-accounts": "Service accounts",
"sign-out": "Sign out",
"snapshots": "Snapshots",
"starred": "Starred",
"starred-empty": "Your starred dashboards will appear here",
"teams": "Teams",
"users": "Users"
"admin": {
"subtitle": "Manage server-wide settings and access to resources such as organizations, users, and licenses",
"title": "Server admin"
},
"alerting": {
"subtitle": "Learn about problems in your systems moments after they occur",
"title": "Alerting"
},
"alerting-admin": {
"title": "Admin"
},
"alerting-am-routes": {
"subtitle": "Determine how alerts are routed to contact points",
"title": "Notification policies"
},
"alerting-channels": {
"title": "Notification channels"
},
"alerting-groups": {
"subtitle": "See grouped alerts from an Alertmanager instance",
"title": "Groups"
},
"alerting-legacy": {
"title": "Alerting (legacy)"
},
"alerting-list": {
"subtitle": "Rules that determine whether an alert will fire",
"title": "Alert rules"
},
"alerting-receivers": {
"subtitle": "Decide how your contacts are notified when an alert fires",
"title": "Contact points"
},
"alerting-silences": {
"subtitle": "Stop notifications from one or more alerting rules",
"title": "Silences"
},
"alerts-and-incidents": {
"subtitle": "Alerting and incident management apps",
"title": "Alerts & incidents"
},
"api-keys": {
"subtitle": "Manage and create API keys that are used to interact with Grafana HTTP APIs",
"title": "API keys"
},
"apps": {
"subtitle": "App plugins that extend the Grafana experience",
"title": "Apps"
},
"config": {
"title": "Configuration"
},
"correlations": {
"subtitle": "Add and configure correlations",
"title": "Correlations"
},
"create": {
"title": "Create"
},
"create-alert": {
"title": "New alert rule"
},
"create-dashboard": {
"title": "Dashboard"
},
"create-folder": {
"title": "Folder"
},
"create-import": {
"title": "Import"
},
"dashboards": {
"subtitle": "Create and manage dashboards to visualize your data",
"title": "Dashboards"
},
"datasources": {
"subtitle": "Add and configure data sources",
"title": "Data sources"
},
"explore": {
"title": "Explore"
},
"global-orgs": {
"subtitle": "Isolated instances of Grafana running on the same server",
"title": "Organizations"
},
"global-users": {
"subtitle": "Manage and create users across the whole Grafana server",
"title": "Users"
},
"help": {
"title": "Help"
},
"help/community": "Community",
"help/documentation": "Documentation",
"help/keyboard-shortcuts": "Keyboard shortcuts",
"help/support": "Support",
"home": {
"title": "Home"
},
"library-panels": {
"subtitle": "Reusable panels that can be added to multiple dashboards",
"title": "Library panels"
},
"live": {
"title": "Event streaming"
},
"live-cloud": {
"title": "Cloud"
},
"live-pipeline": {
"title": "Pipeline"
},
"live-status": {
"title": "Status"
},
"manage-dashboards": {
"title": "Browse"
},
"monitoring": {
"subtitle": "Monitoring and infrastructure apps",
"title": "Monitoring"
},
"new-dashboard": {
"title": "New dashboard"
},
"new-folder": {
"title": "New folder"
},
"org-settings": {
"subtitle": "Manage preferences across an organization",
"title": "Preferences"
},
"playlists": {
"subtitle": "Groups of dashboards that are displayed in a sequence",
"title": "Playlists"
},
"plugins": {
"subtitle": "Extend the Grafana experience with plugins",
"title": "Plugins"
},
"profile/notifications": {
"title": "Notification history"
},
"profile/password": {
"title": "Change password"
},
"profile/settings": {
"title": "Preferences"
},
"profile/switch-org": "Switch organization",
"scenes": {
"title": "Scenes"
},
"search": {
"placeholder": "Search Grafana"
},
"server-settings": {
"subtitle": "View the settings defined in your Grafana config",
"title": "Settings"
},
"service-accounts": {
"subtitle": "Use service accounts to run automated workloads in Grafana",
"title": "Service accounts"
},
"sign-in": "Sign in",
"sign-out": {
"title": "Sign out"
},
"snapshots": {
"subtitle": "Interactive, publically available, point-in-time representations of dashboards",
"title": "Snapshots"
},
"starred": {
"title": "Starred"
},
"starred-empty": {
"title": "Your starred dashboards will appear here"
},
"storage": {
"subtitle": "Manage file storage",
"title": "Storage"
},
"teams": {
"subtitle": "Groups of users that have common dashboard and permission needs",
"title": "Teams"
},
"upgrading": {
"title": "Stats and license"
},
"users": {
"subtitle": "Invite and assign roles to users",
"title": "Users"
}
},
"navigation": {
"kiosk": {
"tv-alert": "Press ESC to exit kiosk mode"
}
},
"news": {
"title": "Latest from the blog"
},
"panel": {
"header-menu": {
"inspect": "Inspect",

View File

@ -103,54 +103,209 @@
}
},
"nav": {
"alerting": "",
"alerting-admin": "",
"alerting-am-routes": "",
"alerting-channels": "",
"alerting-groups": "",
"alerting-legacy": "",
"alerting-list": "",
"alerting-receivers": "",
"alerting-silences": "",
"api-keys": "",
"config": "",
"correlations": "",
"create": "",
"create-alert": "",
"create-dashboard": "",
"create-folder": "",
"create-import": "",
"dashboards": "",
"datasources": "",
"explore": "",
"help": "",
"home": "",
"library-panels": "",
"live": "",
"live-cloud": "",
"live-pipeline": "",
"live-status": "",
"manage-dashboards": "",
"new-dashboard": "",
"new-folder": "",
"org-settings": "",
"playlists": "",
"plugins": "",
"profile/password": "",
"profile/settings": "",
"service-accounts": "",
"sign-out": "",
"snapshots": "",
"starred": "",
"starred-empty": "",
"teams": "",
"users": ""
"admin": {
"subtitle": "",
"title": ""
},
"alerting": {
"subtitle": "",
"title": ""
},
"alerting-admin": {
"title": ""
},
"alerting-am-routes": {
"subtitle": "",
"title": ""
},
"alerting-channels": {
"title": ""
},
"alerting-groups": {
"subtitle": "",
"title": ""
},
"alerting-legacy": {
"title": ""
},
"alerting-list": {
"subtitle": "",
"title": ""
},
"alerting-receivers": {
"subtitle": "",
"title": ""
},
"alerting-silences": {
"subtitle": "",
"title": ""
},
"alerts-and-incidents": {
"subtitle": "",
"title": ""
},
"api-keys": {
"subtitle": "",
"title": ""
},
"apps": {
"subtitle": "",
"title": ""
},
"config": {
"title": ""
},
"correlations": {
"subtitle": "",
"title": ""
},
"create": {
"title": ""
},
"create-alert": {
"title": ""
},
"create-dashboard": {
"title": ""
},
"create-folder": {
"title": ""
},
"create-import": {
"title": ""
},
"dashboards": {
"subtitle": "",
"title": ""
},
"datasources": {
"subtitle": "",
"title": ""
},
"explore": {
"title": ""
},
"global-orgs": {
"subtitle": "",
"title": ""
},
"global-users": {
"subtitle": "",
"title": ""
},
"help": {
"title": ""
},
"help/community": "",
"help/documentation": "",
"help/keyboard-shortcuts": "",
"help/support": "",
"home": {
"title": ""
},
"library-panels": {
"subtitle": "",
"title": ""
},
"live": {
"title": ""
},
"live-cloud": {
"title": ""
},
"live-pipeline": {
"title": ""
},
"live-status": {
"title": ""
},
"manage-dashboards": {
"title": ""
},
"monitoring": {
"subtitle": "",
"title": ""
},
"new-dashboard": {
"title": ""
},
"new-folder": {
"title": ""
},
"org-settings": {
"subtitle": "",
"title": ""
},
"playlists": {
"subtitle": "",
"title": ""
},
"plugins": {
"subtitle": "",
"title": ""
},
"profile/notifications": {
"title": ""
},
"profile/password": {
"title": ""
},
"profile/settings": {
"title": ""
},
"profile/switch-org": "",
"scenes": {
"title": ""
},
"search": {
"placeholder": ""
},
"server-settings": {
"subtitle": "",
"title": ""
},
"service-accounts": {
"subtitle": "",
"title": ""
},
"sign-in": "",
"sign-out": {
"title": ""
},
"snapshots": {
"subtitle": "",
"title": ""
},
"starred": {
"title": ""
},
"starred-empty": {
"title": ""
},
"storage": {
"subtitle": "",
"title": ""
},
"teams": {
"subtitle": "",
"title": ""
},
"upgrading": {
"title": ""
},
"users": {
"subtitle": "",
"title": ""
}
},
"navigation": {
"kiosk": {
"tv-alert": ""
}
},
"news": {
"title": ""
},
"panel": {
"header-menu": {
"inspect": "",

View File

@ -103,54 +103,209 @@
}
},
"nav": {
"alerting": "",
"alerting-admin": "",
"alerting-am-routes": "",
"alerting-channels": "",
"alerting-groups": "",
"alerting-legacy": "",
"alerting-list": "",
"alerting-receivers": "",
"alerting-silences": "",
"api-keys": "",
"config": "",
"correlations": "",
"create": "",
"create-alert": "",
"create-dashboard": "",
"create-folder": "",
"create-import": "",
"dashboards": "",
"datasources": "",
"explore": "",
"help": "",
"home": "",
"library-panels": "",
"live": "",
"live-cloud": "",
"live-pipeline": "",
"live-status": "",
"manage-dashboards": "",
"new-dashboard": "",
"new-folder": "",
"org-settings": "",
"playlists": "",
"plugins": "",
"profile/password": "",
"profile/settings": "",
"service-accounts": "",
"sign-out": "",
"snapshots": "",
"starred": "",
"starred-empty": "",
"teams": "",
"users": ""
"admin": {
"subtitle": "",
"title": ""
},
"alerting": {
"subtitle": "",
"title": ""
},
"alerting-admin": {
"title": ""
},
"alerting-am-routes": {
"subtitle": "",
"title": ""
},
"alerting-channels": {
"title": ""
},
"alerting-groups": {
"subtitle": "",
"title": ""
},
"alerting-legacy": {
"title": ""
},
"alerting-list": {
"subtitle": "",
"title": ""
},
"alerting-receivers": {
"subtitle": "",
"title": ""
},
"alerting-silences": {
"subtitle": "",
"title": ""
},
"alerts-and-incidents": {
"subtitle": "",
"title": ""
},
"api-keys": {
"subtitle": "",
"title": ""
},
"apps": {
"subtitle": "",
"title": ""
},
"config": {
"title": ""
},
"correlations": {
"subtitle": "",
"title": ""
},
"create": {
"title": ""
},
"create-alert": {
"title": ""
},
"create-dashboard": {
"title": ""
},
"create-folder": {
"title": ""
},
"create-import": {
"title": ""
},
"dashboards": {
"subtitle": "",
"title": ""
},
"datasources": {
"subtitle": "",
"title": ""
},
"explore": {
"title": ""
},
"global-orgs": {
"subtitle": "",
"title": ""
},
"global-users": {
"subtitle": "",
"title": ""
},
"help": {
"title": ""
},
"help/community": "",
"help/documentation": "",
"help/keyboard-shortcuts": "",
"help/support": "",
"home": {
"title": ""
},
"library-panels": {
"subtitle": "",
"title": ""
},
"live": {
"title": ""
},
"live-cloud": {
"title": ""
},
"live-pipeline": {
"title": ""
},
"live-status": {
"title": ""
},
"manage-dashboards": {
"title": ""
},
"monitoring": {
"subtitle": "",
"title": ""
},
"new-dashboard": {
"title": ""
},
"new-folder": {
"title": ""
},
"org-settings": {
"subtitle": "",
"title": ""
},
"playlists": {
"subtitle": "",
"title": ""
},
"plugins": {
"subtitle": "",
"title": ""
},
"profile/notifications": {
"title": ""
},
"profile/password": {
"title": ""
},
"profile/settings": {
"title": ""
},
"profile/switch-org": "",
"scenes": {
"title": ""
},
"search": {
"placeholder": ""
},
"server-settings": {
"subtitle": "",
"title": ""
},
"service-accounts": {
"subtitle": "",
"title": ""
},
"sign-in": "",
"sign-out": {
"title": ""
},
"snapshots": {
"subtitle": "",
"title": ""
},
"starred": {
"title": ""
},
"starred-empty": {
"title": ""
},
"storage": {
"subtitle": "",
"title": ""
},
"teams": {
"subtitle": "",
"title": ""
},
"upgrading": {
"title": ""
},
"users": {
"subtitle": "",
"title": ""
}
},
"navigation": {
"kiosk": {
"tv-alert": ""
}
},
"news": {
"title": ""
},
"panel": {
"header-menu": {
"inspect": "",

View File

@ -103,54 +103,209 @@
}
},
"nav": {
"alerting": "Åľęřŧįʼnģ",
"alerting-admin": "Åđmįʼn",
"alerting-am-routes": "Ńőŧįƒįčäŧįőʼn pőľįčįęş",
"alerting-channels": "Ńőŧįƒįčäŧįőʼn čĥäʼnʼnęľş",
"alerting-groups": "Ğřőūpş",
"alerting-legacy": "Åľęřŧįʼnģ (ľęģäčy)",
"alerting-list": "Åľęřŧ řūľęş",
"alerting-receivers": "Cőʼnŧäčŧ pőįʼnŧş",
"alerting-silences": "Ŝįľęʼnčęş",
"api-keys": "ÅPĨ ĸęyş",
"config": "Cőʼnƒįģūřäŧįőʼn",
"correlations": "Cőřřęľäŧįőʼnş",
"create": "Cřęäŧę",
"create-alert": "Ńęŵ äľęřŧ řūľę",
"create-dashboard": "Đäşĥþőäřđ",
"create-folder": "Főľđęř",
"create-import": "Ĩmpőřŧ",
"dashboards": "Đäşĥþőäřđş",
"datasources": "Đäŧä şőūřčęş",
"explore": "Ēχpľőřę",
"help": "Ħęľp",
"home": "Ħőmę",
"library-panels": "Ŀįþřäřy päʼnęľş",
"live": "Ēvęʼnŧ şŧřęämįʼnģ",
"live-cloud": "Cľőūđ",
"live-pipeline": "Pįpęľįʼnę",
"live-status": "Ŝŧäŧūş",
"manage-dashboards": "ßřőŵşę",
"new-dashboard": "Ńęŵ đäşĥþőäřđ",
"new-folder": "Ńęŵ ƒőľđęř",
"org-settings": "Přęƒęřęʼnčęş",
"playlists": "Pľäyľįşŧş",
"plugins": "Pľūģįʼnş",
"profile/password": "Cĥäʼnģę päşşŵőřđ",
"profile/settings": "Přęƒęřęʼnčęş",
"service-accounts": "Ŝęřvįčę äččőūʼnŧş",
"sign-out": "Ŝįģʼn őūŧ",
"snapshots": "Ŝʼnäpşĥőŧş",
"starred": "Ŝŧäřřęđ",
"starred-empty": "Ÿőūř şŧäřřęđ đäşĥþőäřđş ŵįľľ äppęäř ĥęřę",
"teams": "Ŧęämş",
"users": "Ůşęřş"
"admin": {
"subtitle": "Mäʼnäģę şęřvęř-ŵįđę şęŧŧįʼnģş äʼnđ äččęşş ŧő řęşőūřčęş şūčĥ äş őřģäʼnįžäŧįőʼnş, ūşęřş, äʼnđ ľįčęʼnşęş",
"title": "Ŝęřvęř äđmįʼn"
},
"alerting": {
"subtitle": "Ŀęäřʼn äþőūŧ přőþľęmş įʼn yőūř şyşŧęmş mőmęʼnŧş äƒŧęř ŧĥęy őččūř",
"title": "Åľęřŧįʼnģ"
},
"alerting-admin": {
"title": "Åđmįʼn"
},
"alerting-am-routes": {
"subtitle": "Đęŧęřmįʼnę ĥőŵ äľęřŧş äřę řőūŧęđ ŧő čőʼnŧäčŧ pőįʼnŧş",
"title": "Ńőŧįƒįčäŧįőʼn pőľįčįęş"
},
"alerting-channels": {
"title": "Ńőŧįƒįčäŧįőʼn čĥäʼnʼnęľş"
},
"alerting-groups": {
"subtitle": "Ŝęę ģřőūpęđ äľęřŧş ƒřőm äʼn Åľęřŧmäʼnäģęř įʼnşŧäʼnčę",
"title": "Ğřőūpş"
},
"alerting-legacy": {
"title": "Åľęřŧįʼnģ (ľęģäčy)"
},
"alerting-list": {
"subtitle": "Ŗūľęş ŧĥäŧ đęŧęřmįʼnę ŵĥęŧĥęř äʼn äľęřŧ ŵįľľ ƒįřę",
"title": "Åľęřŧ řūľęş"
},
"alerting-receivers": {
"subtitle": "Đęčįđę ĥőŵ yőūř čőʼnŧäčŧş äřę ʼnőŧįƒįęđ ŵĥęʼn äʼn äľęřŧ ƒįřęş",
"title": "Cőʼnŧäčŧ pőįʼnŧş"
},
"alerting-silences": {
"subtitle": "Ŝŧőp ʼnőŧįƒįčäŧįőʼnş ƒřőm őʼnę őř mőřę äľęřŧįʼnģ řūľęş",
"title": "Ŝįľęʼnčęş"
},
"alerts-and-incidents": {
"subtitle": "Åľęřŧįʼnģ äʼnđ įʼnčįđęʼnŧ mäʼnäģęmęʼnŧ äppş",
"title": "Åľęřŧş & įʼnčįđęʼnŧş"
},
"api-keys": {
"subtitle": "Mäʼnäģę äʼnđ čřęäŧę ÅPĨ ĸęyş ŧĥäŧ äřę ūşęđ ŧő įʼnŧęřäčŧ ŵįŧĥ Ğřäƒäʼnä ĦŦŦP ÅPĨş",
"title": "ÅPĨ ĸęyş"
},
"apps": {
"subtitle": "Åpp pľūģįʼnş ŧĥäŧ ęχŧęʼnđ ŧĥę Ğřäƒäʼnä ęχpęřįęʼnčę",
"title": "Åppş"
},
"config": {
"title": "Cőʼnƒįģūřäŧįőʼn"
},
"correlations": {
"subtitle": "Åđđ äʼnđ čőʼnƒįģūřę čőřřęľäŧįőʼnş",
"title": "Cőřřęľäŧįőʼnş"
},
"create": {
"title": "Cřęäŧę"
},
"create-alert": {
"title": "Ńęŵ äľęřŧ řūľę"
},
"create-dashboard": {
"title": "Đäşĥþőäřđ"
},
"create-folder": {
"title": "Főľđęř"
},
"create-import": {
"title": "Ĩmpőřŧ"
},
"dashboards": {
"subtitle": "Cřęäŧę äʼnđ mäʼnäģę đäşĥþőäřđş ŧő vįşūäľįžę yőūř đäŧä",
"title": "Đäşĥþőäřđş"
},
"datasources": {
"subtitle": "Åđđ äʼnđ čőʼnƒįģūřę đäŧä şőūřčęş",
"title": "Đäŧä şőūřčęş"
},
"explore": {
"title": "Ēχpľőřę"
},
"global-orgs": {
"subtitle": "Ĩşőľäŧęđ įʼnşŧäʼnčęş őƒ Ğřäƒäʼnä řūʼnʼnįʼnģ őʼn ŧĥę şämę şęřvęř",
"title": "Øřģäʼnįžäŧįőʼnş"
},
"global-users": {
"subtitle": "Mäʼnäģę äʼnđ čřęäŧę ūşęřş äčřőşş ŧĥę ŵĥőľę Ğřäƒäʼnä şęřvęř",
"title": "Ůşęřş"
},
"help": {
"title": "Ħęľp"
},
"help/community": "Cőmmūʼnįŧy",
"help/documentation": "Đőčūmęʼnŧäŧįőʼn",
"help/keyboard-shortcuts": "Ķęyþőäřđ şĥőřŧčūŧş",
"help/support": "Ŝūppőřŧ",
"home": {
"title": "Ħőmę"
},
"library-panels": {
"subtitle": "Ŗęūşäþľę päʼnęľş ŧĥäŧ čäʼn þę äđđęđ ŧő mūľŧįpľę đäşĥþőäřđş",
"title": "Ŀįþřäřy päʼnęľş"
},
"live": {
"title": "Ēvęʼnŧ şŧřęämįʼnģ"
},
"live-cloud": {
"title": "Cľőūđ"
},
"live-pipeline": {
"title": "Pįpęľįʼnę"
},
"live-status": {
"title": "Ŝŧäŧūş"
},
"manage-dashboards": {
"title": "ßřőŵşę"
},
"monitoring": {
"subtitle": "Mőʼnįŧőřįʼnģ äʼnđ įʼnƒřäşŧřūčŧūřę äppş",
"title": "Mőʼnįŧőřįʼnģ"
},
"new-dashboard": {
"title": "Ńęŵ đäşĥþőäřđ"
},
"new-folder": {
"title": "Ńęŵ ƒőľđęř"
},
"org-settings": {
"subtitle": "Mäʼnäģę přęƒęřęʼnčęş äčřőşş äʼn őřģäʼnįžäŧįőʼn",
"title": "Přęƒęřęʼnčęş"
},
"playlists": {
"subtitle": "Ğřőūpş őƒ đäşĥþőäřđş ŧĥäŧ äřę đįşpľäyęđ įʼn ä şęqūęʼnčę",
"title": "Pľäyľįşŧş"
},
"plugins": {
"subtitle": "Ēχŧęʼnđ ŧĥę Ğřäƒäʼnä ęχpęřįęʼnčę ŵįŧĥ pľūģįʼnş",
"title": "Pľūģįʼnş"
},
"profile/notifications": {
"title": "Ńőŧįƒįčäŧįőʼn ĥįşŧőřy"
},
"profile/password": {
"title": "Cĥäʼnģę päşşŵőřđ"
},
"profile/settings": {
"title": "Přęƒęřęʼnčęş"
},
"profile/switch-org": "Ŝŵįŧčĥ őřģäʼnįžäŧįőʼn",
"scenes": {
"title": "Ŝčęʼnęş"
},
"search": {
"placeholder": "Ŝęäřčĥ Ğřäƒäʼnä"
},
"server-settings": {
"subtitle": "Vįęŵ ŧĥę şęŧŧįʼnģş đęƒįʼnęđ įʼn yőūř Ğřäƒäʼnä čőʼnƒįģ",
"title": "Ŝęŧŧįʼnģş"
},
"service-accounts": {
"subtitle": "Ůşę şęřvįčę äččőūʼnŧş ŧő řūʼn äūŧőmäŧęđ ŵőřĸľőäđş įʼn Ğřäƒäʼnä",
"title": "Ŝęřvįčę äččőūʼnŧş"
},
"sign-in": "Ŝįģʼn įʼn",
"sign-out": {
"title": "Ŝįģʼn őūŧ"
},
"snapshots": {
"subtitle": "Ĩʼnŧęřäčŧįvę, pūþľįčäľľy äväįľäþľę, pőįʼnŧ-įʼn-ŧįmę řępřęşęʼnŧäŧįőʼnş őƒ đäşĥþőäřđş",
"title": "Ŝʼnäpşĥőŧş"
},
"starred": {
"title": "Ŝŧäřřęđ"
},
"starred-empty": {
"title": "Ÿőūř şŧäřřęđ đäşĥþőäřđş ŵįľľ äppęäř ĥęřę"
},
"storage": {
"subtitle": "Mäʼnäģę ƒįľę şŧőřäģę",
"title": "Ŝŧőřäģę"
},
"teams": {
"subtitle": "Ğřőūpş őƒ ūşęřş ŧĥäŧ ĥävę čőmmőʼn đäşĥþőäřđ äʼnđ pęřmįşşįőʼn ʼnęęđş",
"title": "Ŧęämş"
},
"upgrading": {
"title": "Ŝŧäŧş äʼnđ ľįčęʼnşę"
},
"users": {
"subtitle": "Ĩʼnvįŧę äʼnđ äşşįģʼn řőľęş ŧő ūşęřş",
"title": "Ůşęřş"
}
},
"navigation": {
"kiosk": {
"tv-alert": "Přęşş ĒŜC ŧő ęχįŧ ĸįőşĸ mőđę"
}
},
"news": {
"title": "Ŀäŧęşŧ ƒřőm ŧĥę þľőģ"
},
"panel": {
"header-menu": {
"inspect": "Ĩʼnşpęčŧ",