Update panel localization

This commit is contained in:
Elio Struyf
2023-07-19 19:20:58 -04:00
parent 31a2451482
commit 4dc1016797
11 changed files with 202 additions and 43 deletions

View File

@@ -18,6 +18,7 @@
"common.important": "Important",
"common.sync": "Sync",
"common.slug": "Slug",
"common.support": "Support",
"common.error.message": "Sorry, something went wrong.",
"field.required": "Required field",
@@ -131,7 +132,6 @@
"dashboard.header.tabs.data": "data",
"dashboard.header.tabs.taxonomies": "Taxonomies",
"dashboard.layout.sponsor.support.label": "Support",
"dashboard.layout.sponsor.support.msg": "Support Front Matter",
"dashboard.layout.sponsor.review.label": "Review",
"dashboard.layout.sponsor.review.msg": "Review Front Matter",
@@ -382,6 +382,34 @@
"panel.seoKeywordInfo.validInfo.label": "Used in heading(s)",
"panel.seoKeywordInfo.validInfo.content": "Content",
"panel.baseView.action.startServer": "Start server",
"panel.baseView.action.stopServer": "Stop server"
"panel.seoKeywords.title": "Keywords",
"panel.seoKeywords.header.keyword": "Keyword",
"panel.seoKeywords.header.details": "Details",
"panel.seoKeywords.density": "* A keyword density of 1-1.5% is sufficient in most cases.",
"panel.seoStatus.title": "Recommendations",
"panel.seoStatus.header.property": "Property",
"panel.seoStatus.header.length": "Length",
"panel.seoStatus.header.valid": "Valid",
"panel.seoStatus.seoFieldInfo.characters": "{0} chars",
"panel.seoStatus.seoFieldInfo.words": "{0} words",
"panel.seoStatus.seoFieldInfo.article": "Article length",
"panel.seoStatus.collapsible.title": "SEO Status",
"panel.seoStatus.required": "{0} or {1} is required.",
"panel.slugAction.title": "Optimize slug",
"panel.spinner.loading": "Loading...",
"panel.startServerbutton.start": "Start server",
"panel.startServerbutton.stop": "Stop server",
"panel.tag.add": "Add {0} to your settings",
"panel.tagPicker.inputPlaceholder.empty": "Pick your {0}",
"panel.tagPicker.inputPlaceholder.disabled": "You have reached the limit of {0}",
"panel.tagPicker.ai.suggest": "Use Front Matter AI to suggest {0}",
"panel.tagPicker.ai.generating": "Generating suggestions...",
"panel.tagPicker.limit": "Max.: {0}",
"panel.tagPicker.unkown": "Add the unknown tag"
}

View File

@@ -61,7 +61,7 @@ export const SponsorMsg: React.FunctionComponent<ISponsorMsgProps> = ({
<SponsorLink
title={l10n.t(LocalizationKey.dashboardLayoutSponsorSupportMsg)}
href={SPONSOR_LINK}>
<span>{l10n.t(LocalizationKey.dashboardLayoutSponsorSupportLabel)}</span>{` `}
<span>{l10n.t(LocalizationKey.commonSupport)}</span>{` `}
<HeartIcon className={`h-5 w-5 group-hover:fill-current`} />
</SponsorLink>
<span>

View File

@@ -75,6 +75,10 @@ export enum LocalizationKey {
* Slug
*/
commonSlug = 'common.slug',
/**
* Support
*/
commonSupport = 'common.support',
/**
* Sorry, something went wrong.
*/
@@ -403,10 +407,6 @@ export enum LocalizationKey {
* Taxonomies
*/
dashboardHeaderTabsTaxonomies = 'dashboard.header.tabs.taxonomies',
/**
* Support
*/
dashboardLayoutSponsorSupportLabel = 'dashboard.layout.sponsor.support.label',
/**
* Support Front Matter
*/
@@ -1204,12 +1204,100 @@ export enum LocalizationKey {
* Content
*/
panelSeoKeywordInfoValidInfoContent = 'panel.seoKeywordInfo.validInfo.content',
/**
* Keywords
*/
panelSeoKeywordsTitle = 'panel.seoKeywords.title',
/**
* Keyword
*/
panelSeoKeywordsHeaderKeyword = 'panel.seoKeywords.header.keyword',
/**
* Details
*/
panelSeoKeywordsHeaderDetails = 'panel.seoKeywords.header.details',
/**
* * A keyword density of 1-1.5% is sufficient in most cases.
*/
panelSeoKeywordsDensity = 'panel.seoKeywords.density',
/**
* Recommendations
*/
panelSeoStatusTitle = 'panel.seoStatus.title',
/**
* Property
*/
panelSeoStatusHeaderProperty = 'panel.seoStatus.header.property',
/**
* Length
*/
panelSeoStatusHeaderLength = 'panel.seoStatus.header.length',
/**
* Valid
*/
panelSeoStatusHeaderValid = 'panel.seoStatus.header.valid',
/**
* {0} chars
*/
panelSeoStatusSeoFieldInfoCharacters = 'panel.seoStatus.seoFieldInfo.characters',
/**
* {0} words
*/
panelSeoStatusSeoFieldInfoWords = 'panel.seoStatus.seoFieldInfo.words',
/**
* Article length
*/
panelSeoStatusSeoFieldInfoArticle = 'panel.seoStatus.seoFieldInfo.article',
/**
* SEO Status
*/
panelSeoStatusCollapsibleTitle = 'panel.seoStatus.collapsible.title',
/**
* {0} or {1} is required.
*/
panelSeoStatusRequired = 'panel.seoStatus.required',
/**
* Optimize slug
*/
panelSlugActionTitle = 'panel.slugAction.title',
/**
* Loading...
*/
panelSpinnerLoading = 'panel.spinner.loading',
/**
* Start server
*/
panelBaseViewActionStartServer = 'panel.baseView.action.startServer',
panelStartServerbuttonStart = 'panel.startServerbutton.start',
/**
* Stop server
*/
panelBaseViewActionStopServer = 'panel.baseView.action.stopServer'
panelStartServerbuttonStop = 'panel.startServerbutton.stop',
/**
* Add {0} to your settings
*/
panelTagAdd = 'panel.tag.add',
/**
* Pick your {0}
*/
panelTagPickerInputPlaceholderEmpty = 'panel.tagPicker.inputPlaceholder.empty',
/**
* You have reached the limit of {0}
*/
panelTagPickerInputPlaceholderDisabled = 'panel.tagPicker.inputPlaceholder.disabled',
/**
* Use Front Matter AI to suggest {0}
*/
panelTagPickerAiSuggest = 'panel.tagPicker.ai.suggest',
/**
* Generating suggestions...
*/
panelTagPickerAiGenerating = 'panel.tagPicker.ai.generating',
/**
* Max.: {0}
*/
panelTagPickerLimit = 'panel.tagPicker.limit',
/**
* Add the unknown tag
*/
panelTagPickerUnkown = 'panel.tagPicker.unkown'
}

View File

@@ -2,6 +2,8 @@ import * as React from 'react';
import { SeoKeywordInfo } from './SeoKeywordInfo';
import { VsTable, VsTableBody, VsTableHeader, VsTableHeaderCell } from './VscodeComponents';
import { ErrorBoundary } from '@sentry/react';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../localization';
export interface ISeoKeywordsProps {
keywords: string[] | null;
@@ -50,12 +52,16 @@ const SeoKeywords: React.FunctionComponent<ISeoKeywordsProps> = ({
return (
<div className={`seo__status__keywords`}>
<h4>Keywords</h4>
<h4>{l10n.t(LocalizationKey.panelSeoKeywordsTitle)}</h4>
<VsTable bordered columns={['30%', 'auto']}>
<VsTableHeader slot="header">
<VsTableHeaderCell className={`table__cell`}>Keyword</VsTableHeaderCell>
<VsTableHeaderCell className={`table__cell`}>Details</VsTableHeaderCell>
<VsTableHeaderCell className={`table__cell`}>
{l10n.t(LocalizationKey.panelSeoKeywordsHeaderKeyword)}
</VsTableHeaderCell>
<VsTableHeaderCell className={`table__cell`}>
{l10n.t(LocalizationKey.panelSeoKeywordsHeaderDetails)}
</VsTableHeaderCell>
</VsTableHeader>
<VsTableBody slot="body">
{validateKeywords().map((keyword, index) => {
@@ -70,7 +76,7 @@ const SeoKeywords: React.FunctionComponent<ISeoKeywordsProps> = ({
{data.wordCount && (
<div className={`seo__status__note`}>
* A keyword density of 1-1.5% is sufficient in most cases.
{l10n.t(LocalizationKey.panelSeoKeywordsDensity)}
</div>
)}
</div>

View File

@@ -10,6 +10,8 @@ import { SeoFieldInfo } from './SeoFieldInfo';
import { SeoKeywords } from './SeoKeywords';
import { TagPicker } from './TagPicker';
import { VsTable, VsTableBody, VsTableHeader, VsTableHeaderCell } from './VscodeComponents';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../localization';
export interface ISeoStatusProps {
seo: SEO;
@@ -58,20 +60,26 @@ const SeoStatus: React.FunctionComponent<ISeoStatusProps> = ({
return (
<div>
<div className={`seo__status__details`}>
<h4>Recommendations</h4>
<h4>{l10n.t(LocalizationKey.panelSeoStatusTitle)}</h4>
<VsTable ref={tableRef} bordered zebra>
<VsTableHeader slot="header">
<VsTableHeaderCell className={`table__cell`}>Property</VsTableHeaderCell>
<VsTableHeaderCell className={`table__cell`}>Length</VsTableHeaderCell>
<VsTableHeaderCell className={`table__cell`}>Valid</VsTableHeaderCell>
<VsTableHeaderCell className={`table__cell`}>
{l10n.t(LocalizationKey.panelSeoStatusHeaderProperty)}
</VsTableHeaderCell>
<VsTableHeaderCell className={`table__cell`}>
{l10n.t(LocalizationKey.panelSeoStatusHeaderLength)}
</VsTableHeaderCell>
<VsTableHeaderCell className={`table__cell`}>
{l10n.t(LocalizationKey.panelSeoStatusHeaderValid)}
</VsTableHeaderCell>
</VsTableHeader>
<VsTableBody slot="body">
{data[titleField] && seo.title > 0 && (
<SeoFieldInfo
title={titleField}
value={data[titleField].length}
recommendation={`${seo.title} chars`}
recommendation={l10n.t(LocalizationKey.panelSeoStatusSeoFieldInfoCharacters, seo.title)}
isValid={data[titleField].length <= seo.title}
/>
)}
@@ -80,7 +88,7 @@ const SeoStatus: React.FunctionComponent<ISeoStatusProps> = ({
<SeoFieldInfo
title={`slug`}
value={slug.length}
recommendation={`${seo.slug} chars`}
recommendation={l10n.t(LocalizationKey.panelSeoStatusSeoFieldInfoCharacters, seo.slug)}
isValid={slug.length <= seo.slug}
/>
)}
@@ -89,16 +97,16 @@ const SeoStatus: React.FunctionComponent<ISeoStatusProps> = ({
<SeoFieldInfo
title={descriptionField}
value={data[descriptionField].length}
recommendation={`${seo.description} chars`}
recommendation={l10n.t(LocalizationKey.panelSeoStatusSeoFieldInfoCharacters, seo.description)}
isValid={data[descriptionField].length <= seo.description}
/>
)}
{seo.content > 0 && data?.articleDetails?.wordCount > 0 && (
<SeoFieldInfo
title={`Article length`}
title={l10n.t(LocalizationKey.panelSeoStatusSeoFieldInfoArticle)}
value={data?.articleDetails?.wordCount}
recommendation={`${seo.content} words`}
recommendation={l10n.t(LocalizationKey.panelSeoStatusSeoFieldInfoWords, seo.content)}
/>
)}
</VsTableBody>
@@ -134,11 +142,11 @@ const SeoStatus: React.FunctionComponent<ISeoStatusProps> = ({
};
return (
<Collapsible id={`seo`} title="SEO Status" sendUpdate={pushUpdate}>
<Collapsible id={`seo`} title={l10n.t(LocalizationKey.panelSeoStatusCollapsibleTitle)} sendUpdate={pushUpdate}>
{!title && !data[descriptionField] ? (
<div className={`seo__status__empty`}>
<p>
<b>Title</b> or <b>{descriptionField}</b> is needed.
{l10n.t(LocalizationKey.panelSeoStatusRequired, "Title", descriptionField)}
</p>
</div>
) : (

View File

@@ -2,17 +2,19 @@ import { Messenger } from '@estruyf/vscode/dist/client';
import * as React from 'react';
import { CommandToCode } from '../CommandToCode';
import { ActionButton } from './ActionButton';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../localization';
export interface ISlugActionProps {}
export interface ISlugActionProps { }
const SlugAction: React.FunctionComponent<
ISlugActionProps
> = ({}: React.PropsWithChildren<ISlugActionProps>) => {
> = ({ }: React.PropsWithChildren<ISlugActionProps>) => {
const optimize = () => {
Messenger.send(CommandToCode.updateSlug);
};
return <ActionButton onClick={optimize} title={`Optimize slug`} />;
return <ActionButton onClick={optimize} title={l10n.t(LocalizationKey.panelSlugActionTitle)} />;
};
SlugAction.displayName = 'SlugAction';

View File

@@ -1,11 +1,17 @@
import * as React from 'react';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../localization';
export interface ISpinnerProps {}
export interface ISpinnerProps { }
const Spinner: React.FunctionComponent<ISpinnerProps> = (
props: React.PropsWithChildren<ISpinnerProps>
_: React.PropsWithChildren<ISpinnerProps>
) => {
return <div className="spinner">Loading...</div>;
return (
<div className="spinner">
{l10n.t(LocalizationKey.panelSpinnerLoading)}
</div>
);
};
Spinner.displayName = 'Spinner';

View File

@@ -1,6 +1,8 @@
import * as React from 'react';
import { SPONSOR_LINK } from '../../constants/Links';
import { HeartIcon } from './Icons/HeartIcon';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../localization';
export interface ISponsorMsgProps {
isBacker: boolean | undefined;
@@ -16,7 +18,7 @@ const SponsorMsg: React.FunctionComponent<ISponsorMsgProps> = ({
return (
<p className={`sponsor`}>
<a href={SPONSOR_LINK} title="Support Front Matter">
<span>Support</span> <HeartIcon className={`h-5 w-5 mr-2`} /> <span>FrontMatter</span>
<span>{l10n.t(LocalizationKey.commonSupport)}</span> <HeartIcon className={`h-5 w-5 mr-2`} /> <span>FrontMatter</span>
</a>
</p>
);

View File

@@ -25,8 +25,18 @@ export const StartServerButton: React.FunctionComponent<IStartServerButtonProps>
return startCommand ? (
<>
<button onClick={() => startLocalServer(startCommand)}>{l10n.t(LocalizationKey.panelActionsStartServer)}</button>
<button onClick={() => stopLocalServer()}>{l10n.t(LocalizationKey.panelActionsStopServer)}</button>
<button
title={l10n.t(LocalizationKey.panelStartServerbuttonStart)}
type={`button`}
onClick={() => startLocalServer(startCommand)}>
{l10n.t(LocalizationKey.panelStartServerbuttonStart)}
</button>
<button
title={l10n.t(LocalizationKey.panelStartServerbuttonStop)}
type={`button`}
onClick={() => stopLocalServer()}>
{l10n.t(LocalizationKey.panelStartServerbuttonStop)}
</button>
</>
) : null;
};

View File

@@ -1,5 +1,7 @@
import { PlusIcon, XIcon } from '@heroicons/react/outline';
import * as React from 'react';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../localization';
export interface ITagProps {
className: string;
@@ -13,7 +15,7 @@ export interface ITagProps {
}
const Tag: React.FunctionComponent<ITagProps> = (props: React.PropsWithChildren<ITagProps>) => {
const { value, className, title, onRemove, onCreate, disableConfigurable } = props;
const { value, title, onRemove, onCreate, disableConfigurable } = props;
return (
<>
@@ -21,7 +23,8 @@ const Tag: React.FunctionComponent<ITagProps> = (props: React.PropsWithChildren<
{!disableConfigurable && onCreate && (
<button
className={`tag__create`}
title={`Add ${value} to your settings`}
title={l10n.t(LocalizationKey.panelTagAdd, value)}
type={`button`}
onClick={() => onCreate(value)}
>
<PlusIcon style={{ width: `1rem`, height: `1rem` }} />
@@ -30,7 +33,11 @@ const Tag: React.FunctionComponent<ITagProps> = (props: React.PropsWithChildren<
<div className={`tag__value`}>{value}</div>
<button title={title} className={`tag__delete`} onClick={() => onRemove(value)}>
<button
title={title}
className={`tag__delete`}
type={`button`}
onClick={() => onRemove(value)}>
<XIcon style={{ width: `1rem`, height: `1rem` }} />
</button>
</div>

View File

@@ -13,6 +13,8 @@ import { FieldTitle } from './Fields/FieldTitle';
import { useRecoilValue } from 'recoil';
import { PanelSettingsAtom } from '../state';
import { SparklesIcon } from '@heroicons/react/outline';
import * as l10n from '@vscode/l10n';
import { LocalizationKey } from '../../localization';
export interface ITagPickerProps {
type: TagType;
@@ -244,10 +246,10 @@ const TagPicker: React.FunctionComponent<ITagPickerProps> = ({
const inputPlaceholder = useMemo((): string => {
if (checkIsDisabled()) {
return `You have reached the limit of ${limit} ${label || type.toLowerCase()}`;
return l10n.t(LocalizationKey.panelTagPickerInputPlaceholderDisabled, `${limit} ${label || type.toLowerCase()}`);
}
return `Pick your ${label || type.toLowerCase()}`;
return l10n.t(LocalizationKey.panelTagPickerInputPlaceholderEmpty, (label || type.toLowerCase()));
}, [label, type, checkIsDisabled]);
const showRequiredState = useMemo(() => {
@@ -266,7 +268,7 @@ const TagPicker: React.FunctionComponent<ITagPickerProps> = ({
return (
<button
className='metadata_field__title__action'
title={`Use Front Matter AI to suggest ${label?.toLowerCase() || type.toLowerCase()}`}
title={l10n.t(LocalizationKey.panelTagPickerAiSuggest, (label?.toLowerCase() || type.toLowerCase()))}
type='button'
onClick={() => suggestTaxonomy(type)}
disabled={loading}>
@@ -324,7 +326,7 @@ const TagPicker: React.FunctionComponent<ITagPickerProps> = ({
{
loading && (
<div className='metadata_field__loading'>
Generating suggestions...
{l10n.t(LocalizationKey.panelTagPickerAiGenerating)}
</div>
)
}
@@ -335,7 +337,7 @@ const TagPicker: React.FunctionComponent<ITagPickerProps> = ({
{limit !== undefined && limit > 0 ? (
<>
{` `}
<span style={{ fontWeight: 'lighter' }}>(Max.: {limit})</span>
<span style={{ fontWeight: 'lighter' }}>({l10n.t(LocalizationKey.panelTagPickerLimit, limit)})</span>
</>
) : (
``
@@ -393,7 +395,7 @@ const TagPicker: React.FunctionComponent<ITagPickerProps> = ({
{freeform && (
<button
className={`article__tags__input__button`}
title={`Add the unknown tag`}
title={l10n.t(LocalizationKey.panelTagPickerUnkown)}
disabled={!inputValue || checkIsDisabled()}
onClick={() => insertUnkownTag(closeMenu)}
>