Added translation support with react-imp. Added partial Polish translation.

This commit is contained in:
Przemek Wiech 2019-01-31 22:35:16 +01:00
parent 748b603cbb
commit 71e2d0fae1
7 changed files with 120 additions and 37 deletions

View File

@ -10,6 +10,7 @@
"query-string": "^6.2.0",
"react": "latest",
"react-dom": "latest",
"react-intl": "^2.8.0",
"react-router-dom": "^4.3.1",
"semantic-ui-css": "^2.4.1",
"semantic-ui-react": "^0.84.0",
@ -22,6 +23,7 @@
"@types/query-string": "^6.2.0",
"@types/react": "*",
"@types/react-dom": "*",
"@types/react-intl": "^2.3.15",
"@types/react-router-dom": "^4.3.1",
"@types/jest": "*",
"@types/node": "*",
@ -35,7 +37,7 @@
"start": "react-scripts-ts start",
"build": "react-scripts-ts build",
"test": "react-scripts-ts test --env=jsdom",
"prettier": "prettier --write src/**/*.{ts,tsx}",
"prettier": "prettier --write src/**/*.{ts,tsx,json}",
"predeploy": "npm run build",
"deploy": "gh-pages -d build"
},

View File

@ -1,21 +1,35 @@
import * as locale_en from 'react-intl/locale-data/en';
import * as locale_pl from 'react-intl/locale-data/pl';
import * as messages_pl from './translations/pl.json';
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import {addLocaleData} from 'react-intl';
import {ChartView} from './chart_view';
import {HashRouter as Router, Route, Switch} from 'react-router-dom';
import {IntlProvider} from 'react-intl';
import {Intro} from './intro';
import {TopBar} from './top_bar';
import 'semantic-ui-css/semantic.min.css';
import './index.css';
import 'semantic-ui-css/semantic.min.css';
addLocaleData([...locale_en, ...locale_pl]);
const messages = {
pl: messages_pl,
};
const language = navigator.language && navigator.language.split(/[-_]/)[0];
ReactDOM.render(
<Router>
<div className="root">
<Route component={TopBar} />
<Switch>
<Route exact path="/" component={Intro} />
<Route exact path="/view" component={ChartView} />
</Switch>
</div>
</Router>,
<IntlProvider locale={language} messages={messages[language]}>
<Router>
<div className="root">
<Route component={TopBar} />
<Switch>
<Route exact path="/" component={Intro} />
<Route exact path="/view" component={ChartView} />
</Switch>
</div>
</Router>
</IntlProvider>,
document.querySelector('#root'),
);

View File

@ -1,6 +1,7 @@
import * as queryString from 'query-string';
import * as React from 'react';
import {Card} from 'semantic-ui-react';
import {FormattedMessage} from 'react-intl';
import {Link} from 'react-router-dom';
/** Link that loads a GEDCOM file from URL. */
@ -18,25 +19,49 @@ function GedcomLink(props: {url: string; text: string}) {
export function Intro() {
return (
<Card className="intro">
<Card.Content header="Topola Genealogy Viewer" />
<Card.Content>
<Card.Header>
<FormattedMessage
id="intro.title"
defaultMessage="Topola Genealogy Viewer"
/>
</Card.Header>
</Card.Content>
<Card.Content>
<p>
Topola Genealogy is a genealogy tree viewer that lets you browse the
structure of the family.
<FormattedMessage
id="intro.description"
defaultMessage={
'Topola Genealogy is a genealogy tree viewer that lets you' +
' browse the structure of the family.'
}
/>
</p>
<p>
Use the LOAD FROM URL or LOAD FROM FILE buttons above to load a GEDCOM
file. You can export a GEDCOM file from most of the existing genealogy
programs and web sites.
<FormattedMessage
id="intro.instructions"
defaultMessage={
'Use the LOAD FROM URL or LOAD FROM FILE buttons above to load' +
' a GEDCOM file. You can export a GEDCOM file from most of the' +
' existing genealogy programs and web sites.'
}
/>
</p>
<p>
<FormattedMessage
id="intro.examples"
defaultMessage={
'Here are some examples from the web that you can view:'
}
/>
</p>
<p>Here are some examples from the web that you can view:</p>
<ul>
<li>
<GedcomLink
url="http://genpol.com/module-Downloads-prep_hand_out-lid-32.html"
text="Karol Wojtyła"
/>{' '}
(from{' '}
(<FormattedMessage id="intro.from" defaultMessage="from" />{' '}
<a href="http://genpol.com/module-Downloads-display-lid-32.html">
GENPOL
</a>
@ -47,7 +72,7 @@ export function Intro() {
url="https://webtreeprint.com/tp_downloader.php?path=famous_gedcoms/shakespeare.ged"
text="Shakespeare"
/>{' '}
(from{' '}
(<FormattedMessage id="intro.from" defaultMessage="from" />{' '}
<a href="https://webtreeprint.com/tp_famous_gedcoms.php">
webtreeprint.com
</a>
@ -58,7 +83,7 @@ export function Intro() {
url="http://genealogyoflife.com/tng/gedcom/HarryPotter.ged"
text="Harry Potter"
/>{' '}
(from{' '}
(<FormattedMessage id="intro.from" defaultMessage="from" />{' '}
<a href="http://famousfamilytrees.blogspot.com/">
Famous Family Trees
</a>

View File

@ -1,6 +1,7 @@
import * as md5 from 'md5';
import * as queryString from 'query-string';
import * as React from 'react';
import {FormattedMessage} from 'react-intl';
import {Link} from 'react-router-dom';
import {RouteComponentProps} from 'react-router-dom';
import {
@ -86,7 +87,14 @@ export class TopBar extends React.Component<RouteComponentProps, State> {
onClose={() => this.handleClose()}
centered={false}
>
<Header icon="cloud download" content="Load from URL" />
<Header>
<Icon name="cloud download" />
<FormattedMessage
id="load_from_url.title"
defaultMessage="Load from URL"
children={(txt) => txt}
/>
</Header>
<Modal.Content>
<Form onSubmit={() => this.handleLoad()}>
<Input
@ -95,22 +103,33 @@ export class TopBar extends React.Component<RouteComponentProps, State> {
onChange={(e) => this.handleUrlChange(e)}
ref={(ref) => (this.inputRef = ref!)}
/>
<p className="comment">
Data from the URL will be loaded through{' '}
<a href="https://cors-anywhere.herokuapp.com/">
cors-anywhere.herokuapp.com
</a>{' '}
to avoid CORS issues.
<p>
<FormattedMessage
id="load_from_url.comment"
defaultMessage={
'Data from the URL will be loaded through {link} to avoid CORS issues.'
}
values={{
link: (
<a href="https://cors-anywhere.herokuapp.com/">
cors-anywhere.herokuapp.com
</a>
),
}}
/>
</p>
</Form>
</Modal.Content>
<Modal.Actions>
<Button
secondary
content="Cancel"
onClick={() => this.handleClose()}
/>
<Button primary content="Load" onClick={() => this.handleLoad()} />
<Button secondary onClick={() => this.handleClose()}>
<FormattedMessage
id="load_from_url.cancel"
defaultMessage="Cancel"
/>
</Button>
<Button primary onClick={() => this.handleLoad()}>
<FormattedMessage id="load_from_url.load" defaultMessage="Load" />
</Button>
</Modal.Actions>
</Modal>
);
@ -124,7 +143,10 @@ export class TopBar extends React.Component<RouteComponentProps, State> {
</Link>
<Menu.Item as="a" onClick={() => this.handleLoadFromUrl()}>
<Icon name="cloud download" />
Load from URL
<FormattedMessage
id="menu.load_from_url"
defaultMessage="Load from URL"
/>
</Menu.Item>
<input
className="hidden"
@ -135,7 +157,10 @@ export class TopBar extends React.Component<RouteComponentProps, State> {
<label htmlFor="fileInput">
<Menu.Item as="a">
<Icon name="folder open" />
Load from file
<FormattedMessage
id="menu.load_from_file"
defaultMessage="Load from file"
/>
</Menu.Item>
</label>
<Menu.Item

13
src/translations/pl.json Normal file
View File

@ -0,0 +1,13 @@
{
"menu.load_from_url": "Otwórz URL",
"menu.load_from_file": "Otwórz plik",
"intro.title": "Topola Genealogy",
"intro.description": "Topola Genealogy pozwala przeglądać drzewo genealogiczne w interaktywny sposób.",
"intro.instructions": "Kliknij OTWÓRZ URL lub OTWÓRZ PLIK, aby załadować plik GEDCOM. Większość programów genealogicznych posiada funkcję eksportu do pliku GEDCOM.",
"intro.examples": "Poniżej jest kilka przykładów znalezionych w Internecie:",
"intro.from": "źródło:",
"load_from_url.title": "Otwórz z adresu URL",
"load_from_url.comment": "Dane z podanego adresu URL zostaną załadowane poprzez usługę {link} w celu uniknięcia problemów z CORS.",
"load_from_url.cancel": "Anuluj",
"load_from_url.load": "Otwórz"
}

View File

@ -17,7 +17,8 @@
"noImplicitAny": true,
"strictNullChecks": true,
"suppressImplicitAnyIndexErrors": true,
"noUnusedLocals": true
"noUnusedLocals": true,
"resolveJsonModule": true
},
"exclude": [
"node_modules",

View File

@ -55,5 +55,8 @@
"allow-trailing-underscore",
"allow-pascal-case"
]
},
"linterOptions": {
"exclude": "src/**/*.json"
}
}