Added German language

This commit is contained in:
Sebastian Seedorf
2022-08-20 00:30:49 +02:00
parent f826537aec
commit 3fea0f851f
11 changed files with 155 additions and 33 deletions

View File

@@ -35,20 +35,21 @@ export const FactoryProvider: FC<Props> = ({ children }) => {
const locale = useLocale() const locale = useLocale()
const internationalizedFactories = useMemo(() => { const internationalizedFactories = useMemo(() => {
if (locale !== 'en') if (locale !== 'en')
factories.map( return factories.map(factory => ({
factory => (factory.name = factoryNames[locale]?.[factory.href] ?? factory.name) ...factory,
) name: factoryNames[locale]?.[factory.href] ?? factory.name
}))
return factories return factories
}, [locale]) }, [locale])
const findFactory = useMemo(() => { const findFactory = useMemo(() => {
const detailsMap = Object.fromEntries( const detailsMap = Object.fromEntries(
factories.map((detail: EnrichedEntity) => [detail.href, detail]) internationalizedFactories.map((detail: EnrichedEntity) => [detail.href, detail])
) )
return (uid: string): EnrichedEntity | undefined => { return (uid: string): EnrichedEntity | undefined => {
return detailsMap[uid] return detailsMap[uid]
} }
}, []) }, [internationalizedFactories])
const value: FactoryContextType = useMemo( const value: FactoryContextType = useMemo(
() => ({ () => ({

View File

@@ -9,12 +9,15 @@ import { fixedEncodeURIComponent, uniquify } from '../../../src/utils'
import Link from 'next/link' import Link from 'next/link'
import { useRouter } from 'next/router' import { useRouter } from 'next/router'
import { useFactories } from '../../contexts/FactoryProvider' import { useFactories } from '../../contexts/FactoryProvider'
import { i18n, I18n } from '../../shared/I18n/I18n'
import { useIntl } from 'react-intl'
interface Props { interface Props {
group: Group group: Group
} }
const GroupBoxBase: FC<Props> = ({ group }) => { const GroupBoxBase: FC<Props> = ({ group }) => {
const intl = useIntl()
const { query } = useRouter() const { query } = useRouter()
const { factories, findFactory } = useFactories() const { factories, findFactory } = useFactories()
const { const {
@@ -99,19 +102,25 @@ const GroupBoxBase: FC<Props> = ({ group }) => {
onClick={() => (!isDeleteConfirm ? setDeleteConfirm(true) : removeGroup(name))} onClick={() => (!isDeleteConfirm ? setDeleteConfirm(true) : removeGroup(name))}
style={{ display: 'block' }} style={{ display: 'block' }}
> >
{isDeleteConfirm ? 'Delete GroupBox?' : 'X'} {isDeleteConfirm ? i18n(intl, 'page.home.group.delete.confirmation') : 'X'}
</button> </button>
<h4>Exported Factories</h4> <h4>
<I18n id={'page.home.group.item.export'} />
</h4>
<FactorySelect <FactorySelect
id={name + '-exports'} id={name + '-exports'}
factories={exports} factories={exports}
onSetFactories={setExportFactories} onSetFactories={setExportFactories}
/> />
<h4>Mall Factories</h4> <h4>
<I18n id={'page.home.group.item.mall'} />
</h4>
<FactorySelect id={name + '-malls'} factories={malls} onSetFactories={setMallFactories} /> <FactorySelect id={name + '-malls'} factories={malls} onSetFactories={setMallFactories} />
{inputs.length ? ( {inputs.length ? (
<> <>
<h4>Input Factories ({inputs.length})</h4> <h4>
<I18n id={'page.home.group.item.input'} /> ({inputs.length})
</h4>
<div className={styles.flex}> <div className={styles.flex}>
{inputs.map(input => ( {inputs.map(input => (
<EntitySpan <EntitySpan
@@ -130,7 +139,9 @@ const GroupBoxBase: FC<Props> = ({ group }) => {
) : null} ) : null}
{intermediates.length ? ( {intermediates.length ? (
<> <>
<h4>Intermediate Factories ({intermediates.length})</h4> <h4>
<I18n id={'page.home.group.item.intermediate'} /> ({intermediates.length})
</h4>
<div className={styles.flex}> <div className={styles.flex}>
{intermediates.map(intermediate => ( {intermediates.map(intermediate => (
<EntitySpan <EntitySpan
@@ -144,7 +155,9 @@ const GroupBoxBase: FC<Props> = ({ group }) => {
) : null} ) : null}
{suggestionsExport.length ? ( {suggestionsExport.length ? (
<> <>
<h4>Suggestions (Export)</h4> <h4>
<I18n id={'page.home.group.item.suggestion.export'} />
</h4>
<div className={styles.flex}> <div className={styles.flex}>
{suggestionsExport.map(suggestion => ( {suggestionsExport.map(suggestion => (
<EntitySpan <EntitySpan
@@ -164,7 +177,9 @@ const GroupBoxBase: FC<Props> = ({ group }) => {
) : null} ) : null}
{suggestionMall.length ? ( {suggestionMall.length ? (
<> <>
<h4>Suggestions (Mall)</h4> <h4>
<I18n id={'page.home.group.item.suggestion.mall'} />
</h4>
<div className={styles.flex}> <div className={styles.flex}>
{suggestionMall.map(suggestion => ( {suggestionMall.map(suggestion => (
<EntitySpan <EntitySpan

View File

@@ -36,6 +36,9 @@ export const Home: FC = () => {
<h1> <h1>
<I18n id={'page.home.title'} /> <I18n id={'page.home.title'} />
</h1> </h1>
<p>
<I18n id={'page.home.description'} />
</p>
<button <button
onClick={() => { onClick={() => {
download('factorio-microservices.bin', store()) download('factorio-microservices.bin', store())
@@ -61,7 +64,12 @@ export const Home: FC = () => {
<Link href={{ pathname: '/visualize', query }}>Visualize</Link> <Link href={{ pathname: '/visualize', query }}>Visualize</Link>
<Preferences /> <Preferences />
<fieldset> <fieldset>
<legend>Missing export factories</legend> <legend>
<I18n id={'page.home.group.missing.export.title'} />
</legend>
<span>
<I18n id={'page.home.group.missing.export.description'} />
</span>
<div className={styles.missingFactories}> <div className={styles.missingFactories}>
{missingExport.map(missing => ( {missingExport.map(missing => (
<EntitySpan <EntitySpan
@@ -84,7 +92,12 @@ export const Home: FC = () => {
</div> </div>
</fieldset> </fieldset>
<fieldset> <fieldset>
<legend>Missing mall factories</legend> <legend>
<I18n id={'page.home.group.missing.mall.title'} />
</legend>
<span>
<I18n id={'page.home.group.missing.mall.description'} />
</span>
<div className={styles.missingFactories}> <div className={styles.missingFactories}>
{missingMall.map(missing => ( {missingMall.map(missing => (
<EntitySpan <EntitySpan

View File

@@ -1,15 +1,25 @@
import { FC, useState } from 'react' import { FC, useState } from 'react'
import { FactorySelect } from '../FactorySelect/FactorySelect' import { FactorySelect } from '../FactorySelect/FactorySelect'
import { useGroups } from '../../contexts/GroupProvider' import { useGroups } from '../../contexts/GroupProvider'
import { i18n, I18n } from '../../shared/I18n/I18n'
import { useIntl } from 'react-intl'
export const Preferences: FC = () => { export const Preferences: FC = () => {
const intl = useIntl()
const { addGroup, baseFactories, setBaseFactories, ignoredFactories, setIgnoredFactories } = const { addGroup, baseFactories, setBaseFactories, ignoredFactories, setIgnoredFactories } =
useGroups() useGroups()
const [newGroupValue, setNewGroupValue] = useState('New group') const [newGroupValue, setNewGroupValue] = useState(
i18n(intl, 'page.home.group.add.default_group_name')
)
return ( return (
<> <>
<fieldset> <fieldset>
<legend>Basic Values</legend> <legend>
<I18n id={'page.home.pref.basic.title'} />
</legend>
<span>
<I18n id={'page.home.pref.basic.description'} />
</span>
<FactorySelect <FactorySelect
id={'baseFactoriesSelect'} id={'baseFactoriesSelect'}
factories={baseFactories} factories={baseFactories}
@@ -18,7 +28,12 @@ export const Preferences: FC = () => {
/> />
</fieldset> </fieldset>
<fieldset> <fieldset>
<legend>Ignored Values</legend> <legend>
<I18n id={'page.home.pref.ignored.title'} />
</legend>
<span>
<I18n id={'page.home.pref.ignored.description'} />
</span>
<FactorySelect <FactorySelect
id={'ignoredFactoriesSelect'} id={'ignoredFactoriesSelect'}
factories={ignoredFactories} factories={ignoredFactories}
@@ -26,7 +41,9 @@ export const Preferences: FC = () => {
/> />
</fieldset> </fieldset>
<fieldset> <fieldset>
<legend>Add new groups</legend> <legend>
<I18n id={'page.home.group.add.title'} />
</legend>
<input value={newGroupValue} onChange={e => setNewGroupValue(e.target.value)} /> <input value={newGroupValue} onChange={e => setNewGroupValue(e.target.value)} />
<button <button
disabled={!newGroupValue} disabled={!newGroupValue}
@@ -35,7 +52,7 @@ export const Preferences: FC = () => {
setNewGroupValue('New group') setNewGroupValue('New group')
}} }}
> >
Add group &quot;{newGroupValue}&quot; <I18n id={'page.home.group.add.button_text'} values={{ name: newGroupValue }} />
</button> </button>
</fieldset> </fieldset>
</> </>

View File

@@ -1,11 +1,20 @@
import { FC } from 'react' import { ComponentProps, FC } from 'react'
import { FormattedMessage } from 'react-intl' import { FormattedMessage, IntlShape } from 'react-intl'
import { useMessages } from '../../../src/i18n' import { useMessages } from '../../../src/i18n'
import { FormatXMLElementFn, PrimitiveType } from 'intl-messageformat'
interface Props { interface Props extends ComponentProps<typeof FormattedMessage> {
id: keyof ReturnType<typeof useMessages>['en'] id: keyof ReturnType<typeof useMessages>['en']
} }
export const I18n: FC<Props> = ({ id }) => { export const I18n: FC<Props> = ({ children, ...props }) => {
return <FormattedMessage id={id} /> return <FormattedMessage {...props}>{children}</FormattedMessage>
}
export const i18n = (
intl: IntlShape,
id: keyof ReturnType<typeof useMessages>['en'],
values?: Record<string, PrimitiveType | FormatXMLElementFn<string, string>>
) => {
return intl.formatMessage({ id }, values, { ignoreTag: true })
} }

View File

@@ -19,7 +19,8 @@ const nextConfig = {
}, },
i18n: { i18n: {
locales: ['en', 'de', 'nl'], locales: ['en', 'de', 'nl'],
defaultLocale: 'en' defaultLocale: 'en',
localeDetection: false
} }
} }

22
pages/_document.tsx Normal file
View File

@@ -0,0 +1,22 @@
import { DocumentProps, Head, Html, Main, NextScript } from 'next/document'
import { IntlProvider } from 'react-intl'
import { useMessages } from '../src/i18n'
import { FC } from 'react'
const MyDocument: FC<DocumentProps> = ({ locale: _locale }) => {
const messages = useMessages()
const locale = _locale ?? '' in messages ? (_locale as keyof typeof messages) : 'en'
return (
<IntlProvider locale={locale} messages={messages[locale]}>
<Html lang={locale}>
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
</IntlProvider>
)
}
export default MyDocument

View File

@@ -1,15 +1,18 @@
import type { NextPage } from 'next' import type { NextPage } from 'next'
import Head from 'next/head'
import { Home } from '../components/home/Home' import { Home } from '../components/home/Home'
import { GroupProvider } from '../components/contexts/GroupProvider' import { GroupProvider } from '../components/contexts/GroupProvider'
import { getServerSidePropsGroupProvider, PropsGroupProvider } from '../src/getServerSideProps' import { getServerSidePropsGroupProvider, PropsGroupProvider } from '../src/getServerSideProps'
import Head from 'next/head'
import { useIntl } from 'react-intl'
import { i18n } from '../components/shared/I18n/I18n'
const Page: NextPage<PropsGroupProvider> = ({ id, ...initial }) => { const Page: NextPage<PropsGroupProvider> = ({ id, ...initial }) => {
const intl = useIntl()
return ( return (
<GroupProvider id={id} initial={initial}> <GroupProvider id={id} initial={initial}>
<Head> <Head>
<title>Factorio Microservices</title> <title>{i18n(intl, 'page.home.head.title')}</title>
<meta name='description' content='Create Factorio microservices' /> <meta name='description' content={i18n(intl, 'page.home.head.meta.description')} />
</Head> </Head>
<Home /> <Home />
</GroupProvider> </GroupProvider>

View File

@@ -1,3 +1,25 @@
{ {
"page.home.title": "Factorio-Microservices" "page.home.head.title": "Factorio Mikroservices",
"page.home.head.meta.description": "Fasse Factorio Fabriken zu Microservices zusammen",
"page.home.title": "Factorio Mikroservices",
"page.home.description": "Auf dieser Seite kannst du alle Einstellungen vornehmen. Gruppiere alle Fabriken zu Microservices zusammen. Ein Microservice ist eine Ansammlung bestimmter Montagemaschinen und anderen Fertigungen, die sich Eingaben (durch Züge) teilen. Optimale Gruppen sollten daher nur wenige Eingaben haben und viele Gegenstände produzieren. \"Exportierte Fabriken\" sind Ausgaben, die z.B. mit Zügen abgeholt, und für andere Services als Eingabe zu Verfügung stehen. \"Mall-Fabriken\" stellen mit Anbieterkisten die Waren zur Abholung durch den Spieler oder Roboter zur Verfügung. Die benötigten Eingabe-und Zwischenfabriken werden automatisch berechnet.",
"page.home.pref.basic.title": "Grundlegende Waren",
"page.home.pref.basic.description": "Grundlegende Waren können nicht in Fabriken hergestellt werden. Es kann sinnvoll sein hier z.B. Eisenplatten hinzuzufügen, wenn jene direkt beim Erz hergestellt werden.",
"page.home.pref.ignored.title": "Ignorierte Waren",
"page.home.pref.ignored.description": "Waren, die in in der Mall hergestellt werden sollen (z.B. Befeuerter Greifarm, weil es nicht benötigt wird) und auch nicht zwischen den Mikroservices exportiert werden sollen (z.B. Zahnräder, weil die bei Bedarf in der Fabrik selbst als Zwischenprodukt hergestellt wird).",
"page.home.group.add.title": "Neue Gruppe hinzufügen",
"page.home.group.add.default_group_name": "Neue Gruppe",
"page.home.group.add.button_text": "Gruppe \"{name}\" hinzufügen",
"page.home.group.missing.export.title": "Fehlende Export-Fabriken",
"page.home.group.missing.export.description": "Eine Auflistung aller Waren, die keine grundlegenden oder ignorierten Waren sind, und bei noch keiner Gruppe exportiert werden oder als Mall-Fabrik hinzugefügt wurden. Nur in dieser Liste falls von mindestens 3 anderen Waren verwendet.",
"page.home.group.missing.mall.title": "Fehlende Mall-Fabriken",
"page.home.group.missing.mall.description": "Eine Auflistung aller Waren, die keine grundlegenden oder ignorierten Waren sind, und bei noch keiner Gruppe exportiert werden oder als Mall-Fabrik hinzugefügt wurden. Nur in dieser Liste falls von maximal 2 anderen Waren verwendet.",
"page.home.group.missing.none": "Alle Fabriken hinzugefügt!",
"page.home.group.item.export": "Exportierte Waren",
"page.home.group.item.mall": "Waren für die Mall",
"page.home.group.item.input": "Angelieferte Waren",
"page.home.group.item.intermediate": "Zwischenprodukte",
"page.home.group.item.suggestion.export": "Empfohlene Exportwaren",
"page.home.group.item.suggestion.mall": "Empfohlene Mall-Fabriken",
"page.home.group.delete.confirmation": "Gruppe unwiderruflich löschen?"
} }

View File

@@ -1,6 +1,25 @@
{ {
"page.home.head.title": "Next.js i18n example", "page.home.head.title": "Factorio Microservices",
"page.home.head.meta.description": "Next.js i18n example - English", "page.home.head.meta.description": "Group Factorio factories together into microservices",
"page.home.title": "Factorio Microservices", "page.home.title": "Factorio Microservices",
"page.home.description": "You are currently viewing the homepage in English 🚀" "page.home.description": "On this page you can make all settings. Group all factories into microservices. A microservice is a collection of certain assembly machines and other fabrications that share inputs (through trains). Optimal groups should therefore have few inputs and produce many items. \"Exported factories\" are outputs that are picked up by trains, for example, and available to other services as inputs. \"Mall factories\" use vendor crates to make goods available for pickup by the player or robot. The required input and intermediate factories are calculated automatically.",
"page.home.pref.basic.title": "Basic goods",
"page.home.pref.basic.description": "Basic goods cannot be produced in factories. It may make sense to add iron plates here, for example, if they are produced directly at the ore.",
"page.home.pref.ignored.title": "Ignored goods",
"page.home.pref.ignored.description": "Goods that are to be manufactured in in the mall (e.g., burner inserter because it is not needed) and also are not to be exported between microservices (e.g., gears because that is manufactured in the factory itself as an intermediate product when needed).",
"page.home.group.add.title": "Add a new group",
"page.home.group.add.default_group_name": "New Group",
"page.home.group.add.button_text": "Add group \"{name}\"",
"page.home.group.missing.export.title": "Missing export factories",
"page.home.group.missing.export.description": "A listing of all goods that are not basic or ignored goods, and are not yet exported at any group or added as a mall factory. Only in this list if used by at least 3 other goods.",
"page.home.group.missing.mall.title": "Missing mall factories",
"page.home.group.missing.mall.description": "A listing of all goods that are not basic or ignored goods, and are not yet exported at any group or added as a mall factory. Only in this list if used by a maximum of 2 other goods.",
"page.home.group.missing.none": "All factories added!",
"page.home.group.item.export": "Exported goods",
"page.home.group.item.mall": "Mall goods",
"page.home.group.item.input": "Input goods",
"page.home.group.item.intermediate": "Intermediate factories",
"page.home.group.item.suggestion.export": "Suggested export goods",
"page.home.group.item.suggestion.mall": "Suggested mall goods",
"page.home.group.delete.confirmation": "Delete group permanently?"
} }

View File

@@ -7,7 +7,7 @@
"next.config.js", "next.config.js",
"src/backend-custom-server/index", "src/backend-custom-server/index",
"scripts/*", "scripts/*",
"res/*.json" "res/**/*.json"
], ],
"exclude": ["dist", ".next", "out", "node_modules", "cypress"] "exclude": ["dist", ".next", "out", "node_modules", "cypress"]
} }