Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Internationalization #9

Merged
merged 9 commits into from Jan 20, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
19 changes: 18 additions & 1 deletion App.js
@@ -1,11 +1,14 @@
import React from 'react';
import { Text } from 'react-native';
import {
createSwitchNavigator,
createBottomTabNavigator,
createAppContainer
} from 'react-navigation';
import Icon from 'react-native-vector-icons/FontAwesome5';

import i18n from './src/i18n';

import WelcomeScreen from './src/screens/WelcomeScreen';
import PracticeScreen from './src/screens/PracticeScreen';
import ResultsScreen from './src/screens/ResultsScreen';
Expand All @@ -24,21 +27,35 @@ const AppNavigator = createBottomTabNavigator(
Home: {
screen: HomeNavigator,
navigationOptions: {
tabBarLabel: ({ tintColor }) => (
<Text style={{ fontSize: 10, color: tintColor }}>
{i18n.t('navigation.home')}
</Text>
),
tabBarIcon: ({ horizontal, tintColor }) =>
<Icon name="home" size={horizontal ? 20 : 25} color={tintColor} />
}
},
HighScores: {
screen: HighScoresScreen,
navigationOptions: {
tabBarLabel: 'High Scores',
tabBarLabel: ({ tintColor }) => (
<Text style={{ fontSize: 10, color: tintColor }}>
{i18n.t('navigation.highScores')}
</Text>
),
tabBarIcon: ({ horizontal, tintColor }) =>
<Icon name="chart-bar" size={horizontal ? 20 : 25} color={tintColor} />
}
},
Settings: {
screen: SettingsScreen,
navigationOptions: {
tabBarLabel: ({ tintColor }) => (
<Text style={{ fontSize: 10, color: tintColor }}>
{i18n.t('navigation.settings')}
</Text>
),
tabBarIcon: ({ horizontal, tintColor }) =>
<Icon name="cogs" size={horizontal ? 20 : 25} color={tintColor} />
}
Expand Down
5 changes: 5 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Expand Up @@ -7,6 +7,7 @@
"test": "jest"
},
"dependencies": {
"i18n-js": "^3.1.0",
"react": "16.6.0-alpha.8af6728",
"react-native": "0.57.4",
"react-native-gesture-handler": "^1.0.9",
Expand Down
5 changes: 4 additions & 1 deletion src/components/HighScores.js
@@ -1,5 +1,6 @@
import React from 'react';
import { FlatList, View, Text, StyleSheet } from 'react-native';
import i18n from '../i18n';

const DEFAULT_TOTAL_NUMBER = 10;

Expand Down Expand Up @@ -33,7 +34,9 @@ export default HighScores = ({ data, totalNumber }) => {

return (
<View style={styles.container}>
<Text style={styles.header}>High Scores</Text>
<Text style={styles.header}>
{i18n.t('high_scores.title')}
</Text>
<FlatList
data={highScores}
renderItem={
Expand Down
10 changes: 7 additions & 3 deletions src/components/LanguageListItem.js
@@ -1,6 +1,7 @@
import React from 'react';
import { Alert, StyleSheet, Text, TouchableOpacity, View } from 'react-native';
import Icon from 'react-native-vector-icons/Ionicons';
import i18n from '../i18n';

class LanguageListItem extends React.Component {
constructor(props) {
Expand All @@ -11,12 +12,15 @@ class LanguageListItem extends React.Component {

handleLocaleChange() {
Alert.alert(
'Change language?',
i18n.t('language_list.change_language'),
null,
[
{ text: 'Cancel', style: 'cancel' },
{
text: 'Change',
text: i18n.t('language_list.cancel'),
style: 'cancel'
},
{
text: i18n.t('language_list.ok'),
onPress: () => this.props.onChangeLocale(this.props.locale),
style: 'destructive'
}
Expand Down
5 changes: 3 additions & 2 deletions src/components/SettingsList.js
@@ -1,15 +1,16 @@
import React from 'react';
import { Text, View } from 'react-native';
import i18n from '../i18n';

import SettingsListItem from './SettingsListItem';

const settings = [
{
name: 'Display language',
name: i18n.t('settings.display_language'),
screen: 'LanguageSelector'
},
{
name: 'About',
name: i18n.t('settings.about'),
screen: 'About'
}
];
Expand Down
11 changes: 11 additions & 0 deletions src/i18n.js
@@ -0,0 +1,11 @@
import i18n from 'i18n-js';

import en from './locales/en.json';
import de from './locales/de.json';

i18n.defaultLocale = 'en';
i18n.locale = 'de';
i18n.fallbacks = true;
i18n.translations = { en, de };

export default i18n;
34 changes: 34 additions & 0 deletions src/locales/de.json
@@ -0,0 +1,34 @@
{
"appName": "Blitzlesen",
"navigation": {
"home": "Startseite",
"highScores": "Highscores",
"settings": "Einstellungen"
},
"home": {
"welcome": "Willkommen im %{appName}!",
"start_practice": "Trainieren"
},
"practice": {
"next_word": "Weiter"
},
"results": {
"title": "Ergebnisse",
"words_count": "Wörter",
"practice_again": "Nochmal üben"
},
"high_scores": {
"title": "Highscores"
},
"settings": {
"display_language": "Sprache",
"about": "Über uns",
"save_button": "Speichern",
"name_placeholder": "Deine Name"
},
"language_list": {
"change_language": "Sprache ändern?",
"ok": "Ändern",
"cancel": "Stornieren"
}
}
34 changes: 34 additions & 0 deletions src/locales/en.json
@@ -0,0 +1,34 @@
{
"appName": "Blitz Reading",
"navigation": {
"home": "Home",
"highScores": "High Scores",
"settings": "Settings"
},
"home": {
"welcome": "Welcome to %{appName}!",
"start_practice": "Practice"
},
"practice": {
"next_word": "Next"
},
"results": {
"title": "Results",
"words_count": "Words count",
"practice_agagin": "Practice again"
},
"high_scores": {
"title": "High Scores"
},
"settings": {
"display_language": "Display language",
"about": "About",
"save_button": "Save",
"name_placeholder": "Your name"
},
"language_list": {
"change_language": "Change language?",
"ok": "Change",
"cancel": "Cancel"
}
}
102 changes: 102 additions & 0 deletions src/locales/words.de.json
@@ -0,0 +1,102 @@
[
"die",
"der",
"und",
"in",
"zu",
"den",
"das",
"nicht",
"von",
"sie",
"ist",
"des",
"sich",
"mit",
"dem",
"dass",
"er",
"es",
"ein",
"ich",
"auf",
"so",
"eine",
"auch",
"als",
"an",
"nach",
"wie",
"im",
"für",
"man",
"aber",
"aus",
"durch",
"wenn",
"nur",
"war",
"noch",
"werden",
"bei",
"hat",
"wir",
"was",
"wird",
"sein",
"einen",
"welche",
"sind",
"oder",
"um",
"haben",
"einer",
"mir",
"über",
"ihm",
"diese",
"einem",
"ihr",
"uns",
"da",
"zum",
"zur",
"kann",
"doch",
"vor",
"dieser",
"mich",
"ihn",
"du",
"hatte",
"seine",
"mehr",
"am",
"denn",
"nun",
"under",
"sehr",
"selbst",
"schon",
"hier",
"bis",
"habe",
"ihre",
"dann",
"ihnen",
"seiner",
"alle",
"wieder",
"meine",
"Zeit",
"gegen",
"vom",
"ganz",
"einzelnen",
"wo",
"muss",
"ohne",
"eines",
"können",
"sein"
]
File renamed without changes.
3 changes: 2 additions & 1 deletion src/screens/AboutScreen.js
@@ -1,10 +1,11 @@
import React from 'react';
import { Text, View } from 'react-native';
import styles from '../styles';
import i18n from '../i18n';

class AboutScreen extends React.Component {
static navigationOptions = {
title: 'About'
title: i18n.t('settings.about')
};

render() {
Expand Down
3 changes: 2 additions & 1 deletion src/screens/LanguageSelectorScreen.js
@@ -1,5 +1,6 @@
import React from 'react';
import { View } from 'react-native';
import i18n from '../i18n';

import LanguageListItem from '../components/LanguageListItem';

Expand All @@ -17,7 +18,7 @@ const languages = [

class LanguageSelectorScreen extends React.Component {
static navigationOptions = {
title: 'Language'
title: i18n.t('settings.display_language')
};

render() {
Expand Down
9 changes: 7 additions & 2 deletions src/screens/PracticeScreen.js
Expand Up @@ -2,7 +2,10 @@ import React from 'react';
import { Button, View, Text } from 'react-native';
import styles from '../styles';

import allWords from '../words.en.json';
import i18n from '../i18n';

import enWords from '../locales/words.en.json';
import deWords from '../locales/words.de.json';
import shuffle from '../shuffle';

const PRACTICE_TIME = 5 * 1000;
Expand All @@ -23,6 +26,8 @@ export default class PracticeScreen extends React.Component {
})
), PRACTICE_TIME);

const allWords = i18n.locale == 'de' ? deWords : enWords;

const words = shuffle(allWords);
const currentWord = words.shift();

Expand Down Expand Up @@ -51,7 +56,7 @@ export default class PracticeScreen extends React.Component {
<Text style={styles.word}>{this.state.currentWord}</Text>
<Button
onPress={this.onPressNextWord}
title="Next Word"
title={i18n.t("practice.next_word")}
/>
</View>
</View>
Expand Down