React / Redux and Multilingual (Internationalization) Apps - Architecture

后端 未结 7 1269
挽巷
挽巷 2020-12-04 04:43

I\'m building an app that will need to be available in multiple languages and locales.

My question is not purely technical, but rather about the architecture, and th

相关标签:
7条回答
  • 2020-12-04 05:26

    Yet another (light) proposal implemented in Typescript and based on ES6 & Redux & Hooks & JSON with no 3rd party dependencies.

    Since the selected language is loaded in the redux state, changing the language becomes very fast without the need of rendering all pages, but just the affected texts.

    Part 1: Redux setup:

    /src/shared/Types.tsx

    export type Language = 'EN' | 'CA';
    

    /src/store/actions/actionTypes.tsx

    export const SET_LANGUAGE = 'SET_LANGUAGE';
    

    /src/store/actions/language.tsx:

    import * as actionTypes from './actionTypes';
    import { Language } from '../../shared/Types';
    
    export const setLanguage = (language: Language) => ({
       type: actionTypes.SET_LANGUAGE,
       language: language,
    });
    

    /src/store/reducers/language.tsx:

    import * as actionTypes from '../action/actionTypes';
    import { Language } from '../../shared/Types';
    import { RootState } from './reducer';
    import dataEN from '../../locales/en/translation.json';
    import dataCA from '../../locales/ca/translation.json';
    
    type rootState = RootState['language'];
    
    interface State extends rootState { }
    interface Action extends rootState {
        type: string,
    }
    
    const initialState = {
        language: 'EN' as Language,
        data: dataEN,
    };
    
    const setLanguage = (state: State, action: Action) => {
        let data;
        switch (action.language) {
            case 'EN':
                data = dataEN;
                break;
            case 'CA':
                data = dataCA;
                break;
            default:
                break;
        }
        return {
            ...state,
            ...{ language: action.language,
                 data: data,
                }
        };
    };
    
    const reducer = (state = initialState, action: Action) => {
        switch (action.type) {
            case actionTypes.SET_LANGUAGE: return setLanguage(state, action);
            default: return state;
        }
    };
    
    export default reducer;
    

    /src/store/reducers/reducer.tsx

    import { useSelector, TypedUseSelectorHook } from 'react-redux';
    import { Language } from '../../shared/Types';
    
    export interface RootState {
        language: {
            language: Language,
            data: any,
        }
    };
    
    export const useTypedSelector: TypedUseSelectorHook<RootState> = useSelector;
    

    /src/App.tsx

    import React from 'react';
    import { Provider } from 'react-redux';
    import { createStore, combineReducers } from 'redux';
    import languageReducer from './store/reducers/language';
    import styles from './App.module.css';
    
    // Set global state variables through Redux
    const rootReducer = combineReducers({
        language: languageReducer,
    });
    const store = createStore(rootReducer);
    
    const App = () => {
    
        return (
            <Provider store={store}>
                <div className={styles.App}>
                    // Your components
                </div>
            </Provider>
        );
    }
    
    export default App;
    

    Part 2: Dropdown menu with languages. In my case, I put this component within the navigation bar to be able to change the language from any screen:

    /src/components/Navigation/Language.tsx

    import React from 'react';
    import { useDispatch } from 'react-redux';
    import { setLanguage } from '../../store/action/language';
    import { useTypedSelector } from '../../store/reducers/reducer';
    import { Language as Lang } from '../../shared/Types';
    import styles from './Language.module.css';
    
    const Language = () => {
        const dispatch = useDispatch();
        const language = useTypedSelector(state => state.language.language);
        
        return (
            <div>
                <select
                    className={styles.Select}
                    value={language}
                    onChange={e => dispatch(setLanguage(e.currentTarget.value as Lang))}>
                    <option value="EN">EN</option>
                    <option value="CA">CA</option>
                </select>
            </div>
        );
    };
    
    export default Language;
    

    Part 3: JSON files. In this example, just a test value with a couple of languages:

    /src/locales/en/translation.json

    {
        "message": "Welcome"
    }
    

    /src/locales/ca/translation.json

    {
        "message": "Benvinguts"
    }
    

    Part 4: Now, at any screen, you can show the text in the selected language from the redux setup:

    import React from 'react';
    import { useTypedSelector } from '../../store/reducers/reducer';
    
    const Test = () => {
        const t = useTypedSelector(state => state.language.data);
    
        return (
            <div> {t.message} </div>
        )
    }
    
    export default Test;
    

    Sorry for the post extension, but I tried to show the complete setup to clarify all doubts. Once this is done, it is very quick and flexible to add languages and use descriptions anywhere.

    0 讨论(0)
提交回复
热议问题