Skip to content

Commit

Permalink
feat: added internationalization option
Browse files Browse the repository at this point in the history
  • Loading branch information
hristo87 committed May 30, 2024
1 parent ade2b2c commit 1cf8c84
Show file tree
Hide file tree
Showing 10 changed files with 181 additions and 20 deletions.
13 changes: 13 additions & 0 deletions baseProject/src/common/navigation/bottomTab/BottomTabNavigator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,29 @@ import { StackNavigator } from 'common/navigation/stack/StackNavigator';
import { HomePage } from 'features/home/page/HomePage';
import { ScreenName } from 'common/navigation/ScreenName';
import { TabNavigationType } from 'common/navigation/type';
{{#if hasI18n}}
import ChangeLanguage from '../../../i18n/ChangeLanguageButton/ChangeLanguage';
{{/if}}

const Tab = createBottomTabNavigator<TabNavigationType>();
const tabNavOptions: BottomTabNavigationOptions = {
headerShown: false,
};

{{#if hasI18n}}
const languageOptions: BottomTabNavigationOptions = {
headerRight: () => <ChangeLanguage />,
};
{{/if}}

export const BottomTabNavigator = () => {
return (
<Tab.Navigator>
{{#if hasI18n}}
<Tab.Screen name={ScreenName.Home} component={HomePage} options={languageOptions} />
{{else}}
<Tab.Screen name={ScreenName.Home} component={HomePage} />
{{/if}}
<Tab.Screen options={tabNavOptions} name={ScreenName.FancyFeaturesStack} component={StackNavigator} />
</Tab.Navigator>
);
Expand Down
54 changes: 45 additions & 9 deletions baseProject/src/features/home/component/HomeComponent.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
import React, { FunctionComponent, ReactNode } from 'react';
import { ScrollView, {{#unless hasStyledComponents}}StyleSheet, {{/unless}}Text, useColorScheme, View } from 'react-native';
{{#if hasI18n}}
import { useTranslation } from 'react-i18next';
import {
Colors,
Header,
LearnMoreLinks,
} from 'react-native/Libraries/NewAppScreen';
{{else}}
import {
Colors,
DebugInstructions,
Header,
LearnMoreLinks,
ReloadInstructions
} from 'react-native/Libraries/NewAppScreen';
{{/if}}
{{#if hasStyledComponents}}
import styled from 'styled-components/native';
{{/if}}
Expand All @@ -30,17 +39,29 @@ const Section: FunctionComponent<{
);
};

export const HomeComponent = () => {
const isDarkMode = useColorScheme() === 'dark';

const backgroundStyle = {
backgroundColor: isDarkMode ? Colors.darker : Colors.lighter
};

const Body: FunctionComponent = () => {
{{#if hasI18n}}
const { t } = useTranslation();
{{/if}}

return (
<ScrollView contentInsetAdjustmentBehavior="automatic" style={backgroundStyle}>
<Header />
{{#if hasI18n}}
<View>
<Section title={t('Step One')}>
{t('Edit')} {<Text style={styles.highlight}>App.tsx</Text>} {t('Screen Change')}
</Section>
<Section title={t('See Your Changes')}>
{t('Press')} {<Text style={styles.highlight}>Cmd + R</Text>} {t('Simulator')} {t('Reload')}
</Section>
<Section title={t('Debug')}>
{t('Press')} {<Text style={styles.highlight}>Cmd + D</Text>} {t('Simulator')} {t('Or')}{' '}
{<Text style={styles.highlight}>{t('Shake')}</Text>} {t('Dev Menu')}
</Section>
<Section title={t('Learn More')}>{t('Read Docs')}</Section>
<LearnMoreLinks />
</View>
{{else}}
<View>
<Section title="Step One">
Edit {{#if hasStyledComponents}}<HighlightedText>App.tsx</HighlightedText>{{else}}<Text style={styles.highlight}>App.tsx</Text>{{/if}} to change this screen and then come back to see your edits.
</Section>
Expand All @@ -53,6 +74,21 @@ export const HomeComponent = () => {
<Section title="Learn More">Read the docs to discover what to do next:</Section>
<LearnMoreLinks />
</View>
{{/if}}
)
}

export const HomeComponent = () => {
const isDarkMode = useColorScheme() === 'dark';

const backgroundStyle = {
backgroundColor: isDarkMode ? Colors.darker : Colors.lighter
};

return (
<ScrollView contentInsetAdjustmentBehavior="automatic" style={backgroundStyle}>
<Header />
<Body />
</ScrollView>
);
};
Expand Down
30 changes: 30 additions & 0 deletions baseProject/src/i18n/ChangeLanguageButton/ChangeLanguage.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React, { FC, useState } from 'react';
import { StyleSheet, Text, TouchableOpacity } from 'react-native';
import { bg, en } from '../locals';
import i18next from '../i18n.config';

interface ChangeLanguageProps {}

const ChangeLanguage: FC<ChangeLanguageProps> = () => {
const [selectedLocal, setSelectedLocal] = useState(en.locale);

const handlePress = () => {
const newLocal = selectedLocal === en.locale ? bg.locale : en.locale;
i18next.changeLanguage(newLocal);
setSelectedLocal(newLocal);
};

return (
<TouchableOpacity onPress={handlePress} style={styles.container}>
<Text>{selectedLocal}</Text>
</TouchableOpacity>
);
};

const styles = StyleSheet.create({
container: {
marginHorizontal: 10,
},
});

export default ChangeLanguage;
22 changes: 22 additions & 0 deletions baseProject/src/i18n/i18n.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import i18next from 'i18next';
import { initReactI18next } from 'react-i18next';
import { bg, en } from './locals';

export const resources = {
en: {
translation: en,
},
bg: {
translation: bg,
},
};

i18next.use(initReactI18next).init({
debug: true,
resources: resources,
lng: 'en',
fallbackLng: 'en',
compatibilityJSON: 'v3',
});

export default i18next;
16 changes: 16 additions & 0 deletions baseProject/src/i18n/locals/bg.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"locale": "bg",
"Step One": "Първа стъпка",
"Edit": "Редактирай",
"Screen Change": ", за да промениш този екран и после се върни, за да видиш промените си.",
"See Your Changes": "Виж промените си",
"Press": "Натисни",
"Reload": ", за да презаредиш промените в кода.",
"Simulator": "в симулатора",
"Debug": "Отстраняване на грешки",
"Or": "или",
"Shake": "разтърси",
"Dev Menu": "устройство си, за да отвориш менюто за разработчици.",
"Learn More": "Научи повече",
"Read Docs": "Прочети документацията, за да научиш какво да правиш нататък:"
}
16 changes: 16 additions & 0 deletions baseProject/src/i18n/locals/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"locale": "en",
"Step One": "Step One",
"Edit": "Edit",
"Screen Change": "to change this screen and then come back to see your edits.",
"See Your Changes": "See Your Changes",
"Press": "Press",
"Reload": "to reload your app's code.",
"Simulator": "in the simulator",
"Debug": "Debug",
"Or": "or",
"Shake": "Shake",
"Dev Menu": "your device to open the Dev Menu.",
"Learn More": "Learn More",
"Read Docs": "Read the docs to discover what to do next:"
}
2 changes: 2 additions & 0 deletions baseProject/src/i18n/locals/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { default as en } from './en.json';
export { default as bg } from './bg.json';
5 changes: 5 additions & 0 deletions src/tools/dependency-versions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,8 @@ export const reactotronDevDeps = [
'reactotron-react-native',
'reactotron-redux'
];

export const i18nDeps = [
'react-i18next',
'i18next'
]
42 changes: 31 additions & 11 deletions src/tools/options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import {
glueStackUICoreDeps,
storybookDevDeps,
reactotronDevDeps,
lucideIconDeps
lucideIconDeps,
i18nDeps
} from './dependency-versions';

export enum StyleLibraryChoice {
Expand Down Expand Up @@ -48,6 +49,11 @@ export enum ReactNavigationExampleChoice {
WithoutReactNavigationExample = 'Without examples'
}

export enum InternationalizationChoice {
i18n = 'i18n',
noI18n = 'No'
}

// When the user selects an option, the corresponding dependencies are installed
export const SelectionToDependencyNameMap = {
[StyleLibraryChoice.GluestackUICore]: glueStackUICoreDeps,
Expand All @@ -58,6 +64,7 @@ export const SelectionToDependencyNameMap = {
[StateLibraryChoice.ReduxToolkitWithQuery]: reduxDeps,
[ReactNavigationExampleChoice.WithReactNavigationExample]: navigationDeps,
[ReactNavigationExampleChoice.WithoutReactNavigationExample]: navigationDeps,
[InternationalizationChoice.i18n]: i18nDeps,
[IconToolkitChoice.LucideIcons]: lucideIconDeps
};

Expand All @@ -73,8 +80,9 @@ export const SelectionToTemplateParamsMap: Partial<Record<
| StyleLibraryChoice
| StorybookChoice
| StateLibraryChoice
| ReactotronChoice
| ReactNavigationExampleChoice
| InternationalizationChoice
| ReactotronChoice
| IconToolkitChoice,
Partial<TemplateParams>
>> = {
Expand Down Expand Up @@ -109,15 +117,18 @@ export const SelectionToTemplateParamsMap: Partial<Record<
hasRTKQuery: true,
hasReduxToolkit: true
},
[ReactNavigationExampleChoice.WithReactNavigationExample]: {
hasReactNavigationExample: true
},
[InternationalizationChoice.i18n]: {
hasI18n: true
},
[ReactotronChoice.withReactotron]: {
hasReactotron: true
},
[ReactotronChoice.withoutReactotron]: {
hasReactotron: false
},
[ReactNavigationExampleChoice.WithReactNavigationExample]: {
hasReactNavigationExample: true
},
[IconToolkitChoice.LucideIcons]: {
hasIconToolkit: true
},
Expand Down Expand Up @@ -157,7 +168,11 @@ export const SelectionToOptionalFilePathsMap = {
getFullPathMatcher('src/common/navigation/'),
getFullPathMatcher('src/features/fancy-feature/'),
getFullPathMatcher('src/features/another-fancy-feature/')
]
],
[InternationalizationChoice.i18n]: [
getFullPathMatcher('src/i18n/'),
getFullPathMatcher('src/common/navigation/bottomTab/ChangeLanguage.tsx')
],
};

export const gluestackOptions = [
Expand All @@ -179,7 +194,8 @@ export const DefaultTemplateParams: TemplateParams = {
hasRTKQuery: false,
hasReactotron: false,
hasReactNavigationExample: false,
hasIconToolkit: false
hasIconToolkit: false,
hasI18n: false
};

const PromptSelectionOptions = {
Expand All @@ -195,14 +211,18 @@ const PromptSelectionOptions = {
choices: Object.values(StateLibraryChoice),
message: 'State Management:'
},
reactotron: {
choices: Object.values(ReactotronChoice),
message: 'Reactotron:'
},
reactNavigationExample: {
choices: Object.values(ReactNavigationExampleChoice),
message: 'React Navigation:'
},
Internationalization: {
choices: Object.values(InternationalizationChoice),
message: 'Internationalization:'
},
reactotron: {
choices: Object.values(ReactotronChoice),
message: 'Reactotron:'
},
iconToolkit: {
choices: Object.values(IconToolkitChoice),
message: 'Icon Toolkit:'
Expand Down
1 change: 1 addition & 0 deletions src/types/BaseProjectTemplateParams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@ export interface TemplateParams {
hasStyledComponents: boolean;
hasReactNavigationExample: boolean;
hasReactotron: boolean;
hasI18n: boolean;
}

0 comments on commit 1cf8c84

Please sign in to comment.