1
0
Fork 0

wip(lab): Migrated translation to next-i18next

This commit is contained in:
Joost De Cock 2022-02-10 21:40:19 +01:00
parent 538f22a1e6
commit bbb2b2c23f
25 changed files with 72 additions and 71 deletions

View file

@ -4,7 +4,8 @@ import Link from 'next/link'
import { useTranslation } from 'next-i18next' import { useTranslation } from 'next-i18next'
const PatternPicker = ({ app }) => { const PatternPicker = ({ app }) => {
const { t } = useTranslation() const { t } = useTranslation(['app'])
return ( return (
<div className="dropdown"> <div className="dropdown">
<div tabIndex="0" className={` <div tabIndex="0" className={`
@ -13,7 +14,7 @@ const PatternPicker = ({ app }) => {
hover:bg-neutral hover:border-neutral-content hover:bg-neutral hover:border-neutral-content
`}> `}>
<DesignIcon /> <DesignIcon />
<span>Patterns</span> <span>{t('designs')}</span>
</div> </div>
<ul tabIndex="0" className="p-2 shadow menu dropdown-content bg-base-100 rounded-box w-52 overflow-y-scroll navdrop"> <ul tabIndex="0" className="p-2 shadow menu dropdown-content bg-base-100 rounded-box w-52 overflow-y-scroll navdrop">
{Object.keys(app.patterns).map(section => ( {Object.keys(app.patterns).map(section => (

View file

@ -1,7 +1,10 @@
import themes from 'shared/themes/index.js' import themes from 'shared/themes/index.js'
import ThemeIcon from 'shared/components/icons/theme.js' import ThemeIcon from 'shared/components/icons/theme.js'
import { useTranslation } from 'next-i18next'
const ThemePicker = ({ app, className }) => { const ThemePicker = ({ app, className }) => {
const { t } = useTranslation(['app'])
return ( return (
<div className={`dropdown ${className}`}> <div className={`dropdown ${className}`}>
<div tabIndex="0" className={` <div tabIndex="0" className={`
@ -10,10 +13,7 @@ const ThemePicker = ({ app, className }) => {
hover:bg-neutral hover:border-neutral-content hover:bg-neutral hover:border-neutral-content
`}> `}>
<ThemeIcon /> <ThemeIcon />
<span>{app.i18n <span>{t(`${app.theme}Theme`)}</span>
? app.t(`${app.theme}Theme`)
: `${app.theme} Theme`
}</span>
</div> </div>
<ul <ul
tabIndex="0" tabIndex="0"
@ -26,10 +26,7 @@ const ThemePicker = ({ app, className }) => {
className="btn btn-ghost hover:bg-base-200" className="btn btn-ghost hover:bg-base-200"
> >
<span className="text-base-content"> <span className="text-base-content">
{app.i18n {t(`${theme}Theme`)}
? app.t(`${theme}Theme`)
: `${theme} Theme`
}
</span> </span>
</button> </button>
</li> </li>

View file

@ -12,7 +12,6 @@ const DesignOptionList = props => {
const [value, setValue] = useState(val) const [value, setValue] = useState(val)
const handleChange = (newVal) => { const handleChange = (newVal) => {
console.log('setting', newVal)
if (newVal === dflt) reset() if (newVal === dflt) reset()
else { else {
setValue(newVal) setValue(newVal)
@ -47,7 +46,7 @@ const DesignOptionList = props => {
`}> `}>
<>&deg;</> <>&deg;</>
</span> </span>
{t(`options.${props.pattern.config.name}.${props.option}.options.${choice}`)} {props.ot(`${props.option}.o.${choice}`)}
</button> </button>
))} ))}
</div> </div>

View file

@ -52,7 +52,7 @@ const DesignOptionPctDeg = props => {
return ( return (
<div className="py-4 mx-6 border-l-2 pl-2"> <div className="py-4 mx-6 border-l-2 pl-2">
<p className="m-0 p-0 px-2 mb-2 text-neutral-content opacity-60 italic"> <p className="m-0 p-0 px-2 mb-2 text-neutral-content opacity-60 italic">
{t(`options:${props.pattern.config.name}.${props.option}.description`, props.app.locale)} {props.ot(`${props.option}.d`)}
</p> </p>
<div className="flex flex-row justify-between"> <div className="flex flex-row justify-between">
{editOption {editOption

View file

@ -12,7 +12,7 @@ import { useTranslation } from 'next-i18next'
const MeasurementInput = ({ m, gist, app, updateMeasurements }) => { const MeasurementInput = ({ m, gist, app, updateMeasurements }) => {
const { t } = useTranslation(['app', 'measurements']) const { t } = useTranslation(['app', 'measurements'])
const prefix = (app.site === 'org') ? '' : 'https://freesewing.org' const prefix = (app.site === 'org') ? '' : 'https://freesewing.org'
const title = t(m) const title = t(`measurements:${m}`)
const isValid = input => { const isValid = input => {
if (input === '') return '' if (input === '') return ''
return !isNaN(input) return !isNaN(input)
@ -62,10 +62,23 @@ const MeasurementInput = ({ m, gist, app, updateMeasurements }) => {
input input-lg input-bordered grow text-base-content input input-lg input-bordered grow text-base-content
${valid === false && 'input-error'} ${valid === false && 'input-error'}
${valid === true && 'input-success'} ${valid === true && 'input-success'}
border-r-0
`} `}
value={val} value={val}
onChange={update} onChange={update}
/> />
<span role="img" className={`bg-transparent border-y
${valid === false && 'border-error text-neutral-content'}
${valid === true && 'border-success text-neutral-content'}
${valid === '' && 'border-base-200 text-base-content'}
`}>
{valid === ''
? ''
: valid
? '👍'
: '🤔'
}
</span>
<span className={` <span className={`
${valid === false && 'bg-error text-neutral-content'} ${valid === false && 'bg-error text-neutral-content'}
${valid === true && 'bg-success text-neutral-content'} ${valid === true && 'bg-success text-neutral-content'}
@ -74,17 +87,6 @@ const MeasurementInput = ({ m, gist, app, updateMeasurements }) => {
cm cm
</span> </span>
</label> </label>
<label className="label">
<span className="label-text-alt">
{valid === ''
? ''
: valid
? 'Looks good'
: 'Invalid'
}
{val}
</span>
</label>
</div> </div>
) )
} }

View file

@ -52,7 +52,7 @@ const WorkbenchMeasurements = ({ app, pattern, gist, updateGist }) => {
{t('measurements')} {t('measurements')}
</h1> </h1>
<details open> <details open>
<summary><h2 className="inline-block">{t('preloadMeasurements')}</h2></summary> <summary><h2 className="inline-block">{t('cfp:preloadMeasurements')}</h2></summary>
<div className="ml-2 pl-4 border-l-2"> <div className="ml-2 pl-4 border-l-2">
{Object.keys(groups).map(group => ( {Object.keys(groups).map(group => (
<details key={group}> <details key={group}>

View file

@ -17,7 +17,7 @@ const CoreSettingBool = props => {
<SumButton onClick={toggle}> <SumButton onClick={toggle}>
<SumDiv> <SumDiv>
<Deg /> <Deg />
<span>{ t(`settings.${props.setting}.title`) }</span> <span>{ t(`settings:${props.setting}.t`) }</span>
</SumDiv> </SumDiv>
<SecText>{ t(value ? 'yes' : 'no')}</SecText> <SecText>{ t(value ? 'yes' : 'no')}</SecText>
</SumButton> </SumButton>

View file

@ -25,7 +25,7 @@ const CoreSettingList = props => {
return ( return (
<div className="py-4 mx-6 border-l-2 pl-2"> <div className="py-4 mx-6 border-l-2 pl-2">
<p className="m-0 p-0 px-2 mb-2 text-neutral-content opacity-60 italic"> <p className="m-0 p-0 px-2 mb-2 text-neutral-content opacity-60 italic">
{t(`settings:${props.setting}.description`)} {t(`settings:${props.setting}.d`)}
</p> </p>
<div className="flex flex-row"> <div className="flex flex-row">
<div className="grow"> <div className="grow">

View file

@ -29,7 +29,7 @@ const CoreSettingMm = props => {
return ( return (
<div className="py-4 mx-6 border-l-2 pl-2"> <div className="py-4 mx-6 border-l-2 pl-2">
<p className="m-0 p-0 px-2 mb-2 text-neutral-content opacity-60 italic"> <p className="m-0 p-0 px-2 mb-2 text-neutral-content opacity-60 italic">
{t(`settings:${props.setting}.description`)} {t(`settings:${props.setting}.d`)}
</p> </p>
<div className="flex flex-row justify-between"> <div className="flex flex-row justify-between">
<span <span
@ -37,7 +37,7 @@ const CoreSettingMm = props => {
dangerouslySetInnerHTML={{__html: formatMm(min, props.gist.units)}} dangerouslySetInnerHTML={{__html: formatMm(min, props.gist.units)}}
/> />
<span <span
className={`font-bold ${val===dflt ? 'text-secondary' : 'text-accent'}`} className={`font-bold ${val===dflt ? 'text-secondary-focus' : 'text-accent'}`}
dangerouslySetInnerHTML={{__html: formatMm(val, props.gist.units)}} dangerouslySetInnerHTML={{__html: formatMm(val, props.gist.units)}}
/> />
<span <span

View file

@ -28,13 +28,13 @@ const CoreSettingNr = props => {
return ( return (
<div className="py-4 mx-6 border-l-2 pl-2"> <div className="py-4 mx-6 border-l-2 pl-2">
<p className="m-0 p-0 px-2 mb-2 text-neutral-content opacity-60 italic"> <p className="m-0 p-0 px-2 mb-2 text-neutral-content opacity-60 italic">
{t(`settings:${props.setting}.description`)} {t(`settings:${props.setting}.d`)}
</p> </p>
<div className="flex flex-row justify-between"> <div className="flex flex-row justify-between">
<span className="opacity-50"> <span className="opacity-50">
{min} {min}
</span> </span>
<span className={`font-bold ${val===dflt ? 'text-secondary' : 'text-accent'}`}> <span className={`font-bold ${val===dflt ? 'text-secondary-focus' : 'text-accent'}`}>
{val} {val}
</span> </span>
<span className="opacity-50"> <span className="opacity-50">

View file

@ -23,7 +23,7 @@ const CoreSettingOnly = props => {
return ( return (
<div className="py-4 mx-6 border-l-2 pl-2"> <div className="py-4 mx-6 border-l-2 pl-2">
<p className="m-0 p-0 px-2 mb-2 text-neutral-content opacity-60 italic"> <p className="m-0 p-0 px-2 mb-2 text-neutral-content opacity-60 italic">
{t(`settings:only.description`)} {t(`settings:only.d`)}
</p> </p>
<div className="flex flex-row"> <div className="flex flex-row">
<div className="grow"> <div className="grow">
@ -33,7 +33,7 @@ const CoreSettingOnly = props => {
onClick={() => togglePart(part.id)} onClick={() => togglePart(part.id)}
className={` className={`
mr-1 mb-1 text-left text-lg w-full hover:text-secondary-focus px-2 mr-1 mb-1 text-left text-lg w-full hover:text-secondary-focus px-2
${props.gist?.only && props.gist.only.indexOf(part.id) !== -1 && 'font-bold text-secondary'} ${props.gist?.only && props.gist.only.indexOf(part.id) !== -1 && 'font-bold text-secondary-focus'}
`} `}
> >
<span className={` <span className={`

View file

@ -21,7 +21,7 @@ const CoreSettingSaBool = props => {
<SumButton onClick={toggle}> <SumButton onClick={toggle}>
<SumDiv> <SumDiv>
<Deg /> <Deg />
<span>{ t(`settings:sa.title`) }</span> <span>{ t(`settings:sa.t`) }</span>
<span className="ml-4 opacity-50"> <span className="ml-4 opacity-50">
[ { t(`yes`) }/ [ { t(`yes`) }/
{ t(`no`) } ] { t(`no`) } ]

View file

@ -31,7 +31,7 @@ const CoreSettingMm = props => {
return ( return (
<div className="py-4 mx-6 border-l-2 pl-2"> <div className="py-4 mx-6 border-l-2 pl-2">
<p className="m-0 p-0 px-2 mb-2 text-neutral-content opacity-60 italic"> <p className="m-0 p-0 px-2 mb-2 text-neutral-content opacity-60 italic">
{t(`settings.sa.description`)} {t(`settings:sa.d`)}
</p> </p>
<div className="flex flex-row justify-between"> <div className="flex flex-row justify-between">
<span <span
@ -39,7 +39,7 @@ const CoreSettingMm = props => {
dangerouslySetInnerHTML={{__html: formatMm(min, props.gist.units)}} dangerouslySetInnerHTML={{__html: formatMm(min, props.gist.units)}}
/> />
<span <span
className={`font-bold ${val===dflt ? 'text-secondary' : 'text-accent'}`} className={`font-bold ${val===dflt ? 'text-secondary-focus' : 'text-accent'}`}
dangerouslySetInnerHTML={{__html: formatMm(val, props.gist.units)}} dangerouslySetInnerHTML={{__html: formatMm(val, props.gist.units)}}
/> />
<span <span

View file

@ -50,7 +50,7 @@ const settings = {
), ),
only: props => (props.gist?.only && props.gist.only.length > 0) only: props => (props.gist?.only && props.gist.only.length > 0)
? <SecText>{props.gist.only.length}</SecText> ? <SecText>{props.gist.only.length}</SecText>
: <span className="text-secondary">{props.t('default')}</span> : <span className="text-secondary-focus">{props.t('default')}</span>
} }
const inputs = { const inputs = {
@ -100,11 +100,11 @@ const Setting = props => {
{props.setting === 'saMm' {props.setting === 'saMm'
? ( ? (
<> <>
<span>{t(`settings:sa.title`)}</span> <span>{t(`settings:sa.t`)}</span>
<span className="ml-4 opacity-50">[ {t(`size`)} ]</span> <span className="ml-4 opacity-50">[ {t(`size`)} ]</span>
</> </>
) )
: <span>{t(`settings:${props.setting}.title`)}</span> : <span>{t(`settings:${props.setting}.t`)}</span>
} }
</SumDiv> </SumDiv>
<Value setting={props.setting} {...props} t={t}/> <Value setting={props.setting} {...props} t={t}/>

View file

@ -10,7 +10,7 @@ const DesignOptions = props => {
return ( return (
<Details open> <Details open>
<TopSummary icon={<OptionsIcon />}> <TopSummary icon={<OptionsIcon />}>
<TopSumTitle>{('designOptions')}</TopSumTitle> <TopSumTitle>{t('designOptions')}</TopSumTitle>
<Chevron /> <Chevron />
</TopSummary> </TopSummary>
<Ul className="pl-5 list-inside"> <Ul className="pl-5 list-inside">

View file

@ -5,7 +5,7 @@ import { Li, Ul, Details, Summary, SumDiv, Deg } from 'shared/components/workben
import { useTranslation } from 'next-i18next' import { useTranslation } from 'next-i18next'
const OptionGroup = props => { const OptionGroup = props => {
const { t } = useTranslation(['app']) const { t } = useTranslation(['optiongroups'])
const config = props.config || props.pattern.config.optionGroups[props.group] const config = props.config || props.pattern.config.optionGroups[props.group]
return ( return (
<Li> <Li>
@ -14,7 +14,7 @@ const OptionGroup = props => {
<SumDiv> <SumDiv>
<Deg /> <Deg />
<span className="font-bold"> <span className="font-bold">
{ t(`optiongroups.${props.group}`) } { t(props.group) }
</span> </span>
</SumDiv> </SumDiv>
<Chevron /> <Chevron />

View file

@ -4,14 +4,14 @@ import { Li, Ul, Details, Summary, SumButton, SumDiv, Deg } from 'shared/compone
import { useTranslation } from 'next-i18next' import { useTranslation } from 'next-i18next'
const OptionSubGroup = props => { const OptionSubGroup = props => {
const { t } = useTranslation(['app']) const { t } = useTranslation(['optiongroups'])
return Object.keys(props.sub).map(name => ( return Object.keys(props.sub).map(name => (
<Li> <Li>
<Details> <Details>
<Summary> <Summary>
<SumDiv> <SumDiv>
<Deg /> <Deg />
<span className="font-bold">{ t(`optiongroups.${name}`) }</span> <span className="font-bold">{ t(name) }</span>
</SumDiv> </SumDiv>
<Chevron /> <Chevron />
</Summary> </Summary>

View file

@ -14,7 +14,7 @@ const values = {
return ( return (
<span className={ <span className={
val=== props.pattern.config.options[props.option].pct/100 val=== props.pattern.config.options[props.option].pct/100
? 'text-secondary' ? 'text-secondary-focus'
: 'text-accent' : 'text-accent'
}> }>
{formatPercentage(val)} {formatPercentage(val)}
@ -26,17 +26,18 @@ const values = {
) )
}, },
bool: props => { bool: props => {
const { t } = useTranslation(['app'])
const dflt = props.pattern.config.options[props.option].bool const dflt = props.pattern.config.options[props.option].bool
const current = props.gist?.options?.[props.option] const current = props.gist?.options?.[props.option]
return ( return (
<span className={ <span className={
(dflt==current || typeof current === 'undefined') (dflt==current || typeof current === 'undefined')
? 'text-secondary' ? 'text-secondary-focus'
: 'text-accent' : 'text-accent'
}> }>
{props.gist?.options?.[props.option] {props.gist?.options?.[props.option]
? props.t('app.yes') ? t('yes')
: props.t('app.no') : t('no')
} }
</span> </span>
) )
@ -45,22 +46,22 @@ const values = {
const dflt = props.pattern.config.options[props.option].count const dflt = props.pattern.config.options[props.option].count
const current = props.gist?.options?.[props.option] const current = props.gist?.options?.[props.option]
return (dflt==current || typeof current === 'undefined') return (dflt==current || typeof current === 'undefined')
? <span className="text-secondary">{dflt}</span> ? <span className="text-secondary-focus">{dflt}</span>
: <span className="text-accent">{current}</span> : <span className="text-accent">{current}</span>
}, },
list: props => { list: props => {
const dflt = props.pattern.config.options[props.option].dflt const dflt = props.pattern.config.options[props.option].dflt
const current = props.gist?.options?.[props.option] const current = props.gist?.options?.[props.option]
const prefix = `options.${props.pattern.config.name}.${props.option}.options.` const prefix = `${props.option}.o.`
return (dflt==current || typeof current === 'undefined') return (dflt==current || typeof current === 'undefined')
? <span className="text-secondary">{props.t(prefix+dflt)}</span> ? <span className="text-secondary-focus">{props.t(prefix+dflt)}</span>
: <span className="text-accent">{props.t(prefix+current)}</span> : <span className="text-accent">{props.t(prefix+current)}</span>
}, },
deg: props => { deg: props => {
const dflt = props.pattern.config.options[props.option].deg const dflt = props.pattern.config.options[props.option].deg
const current = props.gist?.options?.[props.option] const current = props.gist?.options?.[props.option]
return (dflt==current || typeof current === 'undefined') return (dflt==current || typeof current === 'undefined')
? <span className="text-secondary">{dflt}&deg;</span> ? <span className="text-secondary-focus">{dflt}&deg;</span>
: <span className="text-accent">{current}&deg;</span> : <span className="text-accent">{current}&deg;</span>
}, },
mm: props => { mm: props => {
@ -84,7 +85,7 @@ const inputs = {
const Option = props => { const Option = props => {
const { t } = useTranslation(['app']) const { t } = useTranslation([`o_${props.pattern.config.name}`])
const type = optionType(props.pattern.config.options[props.option]) const type = optionType(props.pattern.config.options[props.option])
const Input = inputs[type] const Input = inputs[type]
const Value = values[type] const Value = values[type]
@ -103,9 +104,7 @@ const Option = props => {
<SumButton onClick={toggleBoolean}> <SumButton onClick={toggleBoolean}>
<SumDiv> <SumDiv>
<Deg /> <Deg />
<span> <span>{t(`${props.option}.t`) }</span>
{ t(`options.${props.pattern.config.name}.${props.option}.title`) }
</span>
</SumDiv> </SumDiv>
<Value type={type} {...props} t={t} /> <Value type={type} {...props} t={t} />
</SumButton> </SumButton>
@ -116,14 +115,12 @@ const Option = props => {
<Summary> <Summary>
<SumDiv> <SumDiv>
<Deg /> <Deg />
<span> <span>{t(`${props.option}.t`)}</span>
{ t(`options.${props.pattern.config.name}.${props.option}.title`) }
</span>
</SumDiv> </SumDiv>
<Value type={type} {...props} t={t} /> <Value type={type} {...props} t={t} />
<Chevron w={6} m={3}/> <Chevron w={6} m={3}/>
</Summary> </Summary>
<Input {...props} /> <Input {...props} ot={t} />
</Details> </Details>
</Li> </Li>
) )

View file

@ -78,8 +78,8 @@ export const TopSumTitle = props => (
</span> </span>
) )
export const SecText = props => props.raw export const SecText = props => props.raw
? <span className="text-secondary" dangerouslySetInnerHTML={{__html: props.raw}} /> ? <span className="text-secondary-focus" dangerouslySetInnerHTML={{__html: props.raw}} />
: <span className="text-secondary">{props.children}</span> : <span className="text-secondary-focus">{props.children}</span>
const WorkbenchMenu = props => { const WorkbenchMenu = props => {
return ( return (

View file

@ -10,7 +10,7 @@ const DisableXray = props => {
<SumDiv> <SumDiv>
<Deg /> <Deg />
<span> <span>
{t('cfp:thingIsEnabled', { thing: t('settings:xray.title') })} {t('cfp:thingIsEnabled', { thing: t('settings:xray.t') })}
</span> </span>
</SumDiv> </SumDiv>
</SumButton> </SumButton>

View file

@ -16,7 +16,7 @@ const Xray = props => {
? ( ? (
<> <>
<span className={`grow ${linkClasses} hover:cursor-resize font-bold uppercase`}> <span className={`grow ${linkClasses} hover:cursor-resize font-bold uppercase`}>
{t('settings:xray.title')} {t('settings:xray.t')}
</span> </span>
<Chevron /> <Chevron />
</> </>
@ -26,10 +26,10 @@ const Xray = props => {
className={`grow ${linkClasses} hover:cursor-resize uppercase font-bold text-left`} className={`grow ${linkClasses} hover:cursor-resize uppercase font-bold text-left`}
onClick={() => props.updateGist(['xray', 'enabled'], true)} onClick={() => props.updateGist(['xray', 'enabled'], true)}
> >
{t('settings:xray.title')} {t('settings:xray.t')}
</button> </button>
<span className="text-normal text-secondary"> <span className="text-normal text-secondary">
{t('cfp:thingIsDisabled', { thing: t('settings:xray.title') })} {t('cfp:thingIsDisabled', { thing: t('settings:xray.t') })}
</span> </span>
</> </>
) )

View file

@ -15,7 +15,7 @@ const types = {
const XrayList = props => { const XrayList = props => {
const { t } = useTranslation(['app', 'parts']) const { t } = useTranslation(['app', 'parts'])
let title = t(`parts.${props.partName}`) let title = t(`parts:${props.partName}`)
if (title !== props.partName || true) title + ` (${props.partName})` if (title !== props.partName || true) title + ` (${props.partName})`
const part = props.gist.xray.parts[props.partName] const part = props.gist.xray.parts[props.partName]

View file

@ -73,7 +73,7 @@ const WorkbenchWrapper = ({ app, pattern }) => {
let draft = false let draft = false
if (mode === 'draft') { if (mode === 'draft') {
draft = new pattern(gist) draft = new pattern(gist)
if (gist?.renderer === 'svg') patternInstance.use(theme) if (gist?.renderer === 'svg') draft.use(theme)
try { draft.draft() } try { draft.draft() }
catch(error) { catch(error) {
console.log('Failed to draft pattern', error) console.log('Failed to draft pattern', error)

View file

@ -36,6 +36,9 @@ const flattenL2 = content => {
for (const l2 in content[l1]) { for (const l2 in content[l1]) {
flat[l1][`${l2}.t`] = content[l1][l2].title flat[l1][`${l2}.t`] = content[l1][l2].title
flat[l1][`${l2}.d`] = content[l1][l2].description flat[l1][`${l2}.d`] = content[l1][l2].description
if (content[l1][l2].options) {
flat[l1][`${l2}.o`] = content[l1][l2].options
}
} }
} }
@ -63,7 +66,7 @@ export const prebuildI18n = async (site) => {
const subNamespaces = flattenL2(loc.topics[namespace]) const subNamespaces = flattenL2(loc.topics[namespace])
for (const subNamespace in subNamespaces) { for (const subNamespace in subNamespaces) {
writeJson( writeJson(
site, locale, 'o.'+subNamespace, site, locale, 'o_'+subNamespace,
subNamespaces[subNamespace] subNamespaces[subNamespace]
) )
} }

View file

@ -65,6 +65,7 @@ documentationForDevelopers: Documentation for developers
documentationForEditors: Documentation for editors documentationForEditors: Documentation for editors
documentationForTranslators: Documentation for translators documentationForTranslators: Documentation for translators
documentationOverview: Documentation overview documentationOverview: Documentation overview
dolls: Dolls
download: Download download: Download
draft: Draft draft: Draft
draftPattern: 'Draft {pattern}' draftPattern: 'Draft {pattern}'
@ -87,6 +88,7 @@ forgotLoginInstructions: "If you don't remember your password, enter your userna
freesewing: Freesewing freesewing: Freesewing
freesewingOnGithub: Freesewing on GitHub freesewingOnGithub: Freesewing on GitHub
garmentPatterns: Garment Patterns garmentPatterns: Garment Patterns
giants: Giants
github: GitHub github: GitHub
goAheadWeWillWait: Go ahead, we'll wait. goAheadWeWillWait: Go ahead, we'll wait.
goodJob: Good job goodJob: Good job
@ -221,7 +223,7 @@ whatIsThis: What is this?
withBreasts: With breasts withBreasts: With breasts
withoutBreasts: Without breasts withoutBreasts: Without breasts
yay: Yay! yay: Yay!
yes: "Yes" # Keep in quotes or it will evaluate to false yes: "Yes" # Keep in quotes or it will evaluate to true
youAreAPatron: You are a patron youAreAPatron: You are a patron
youAreNotAPatron: Your are not a patron youAreNotAPatron: Your are not a patron
youAreNotLoggedIn: You are not logged in youAreNotLoggedIn: You are not logged in