Skip to content
Snippets Groups Projects
Commit e48fc909 authored by tkach-as's avatar tkach-as
Browse files

feat: added i18n

parent e57178c8
No related branches found
No related tags found
No related merge requests found
Showing
with 285 additions and 33 deletions
import React from 'react';
import logo from './logo.svg';
import './App.css';
import { useTranslation } from 'react-i18next'
import LanguageItems from './components/language-items/LanguageItems'
import ToDoList from './components/todo-list/ToDoList'
import ToDoAdd from './components/todo-add/ToDoAdd'
function App() {
const { t } = useTranslation(['home', 'buttons'])
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.tsx</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
<div
style={{
display: 'flex',
flexDirection: 'column',
justifyContent: 'space-between',
gap: '5px',
alignItems: 'center',
}}
>
<h3 style={{ textAlign: 'center' }}>ToDo List App</h3>
<LanguageItems />
<div>
{t('title', { ns: ['home'] })} <br />
</div>
<ToDoAdd />
<ToDoList />
</div>
);
)
}
export default App;
export default App
import { useTranslation } from 'react-i18next'
const LanguageItems = () => {
const { i18n } = useTranslation()
const changeLanguage = (lg: string) => {
i18n.changeLanguage(lg)
}
return (
<div>
<button onClick={() => changeLanguage('en')}>En</button>
<button onClick={() => changeLanguage('es')}>Es</button>
<button onClick={() => changeLanguage('ua')}>Ua</button>
</div>
)
}
export default LanguageItems
import { useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useDispatch } from 'react-redux'
import { AppDispatch } from '../../redux/store'
import { addTodo } from '../../redux/todoSlice'
const ToDoAdd = () => {
const [todoDescription, setTodoDescription] = useState('')
const dispatch = useDispatch<AppDispatch>()
const { t } = useTranslation(['home', 'buttons'])
const handleChange: React.ChangeEventHandler<HTMLInputElement> = (e) => {
setTodoDescription(e.target.value)
}
const saveTodo = (): void => {
dispatch(addTodo(todoDescription))
setTodoDescription('')
}
return (
<div>
<input
placeholder='To Do Item'
onChange={handleChange}
value={todoDescription}
/>
<button onClick={saveTodo}>{t('buttons.ok', { ns: ['buttons'] })}</button>
</div>
)
}
export default ToDoAdd
import { useTranslation } from 'react-i18next'
import { ToDo } from '../../models/ToDo'
interface ITodoItem extends ToDo {
toggleTodo: (id: number) => void
removeTodo: (id: number) => void
}
const ToDoItem: React.FC<ITodoItem> = (props) => {
const { id, description, completed, toggleTodo, removeTodo } = props
const { t } = useTranslation(['home', 'buttons'])
return (
<div
style={{
display: 'flex',
flexDirection: 'row',
gap: '5px',
alignItems: 'center',
}}
>
<input
type='checkbox'
checked={completed}
onChange={() => toggleTodo(id)}
/>
<p
style={{
textDecoration: completed ? 'line-through' : 'none',
}}
>
{description}
</p>
<button
onClick={() => removeTodo(id)}
style={{
height: '20px',
}}
>
{t('buttons.cancel', { ns: ['buttons'] })}
</button>
</div>
)
}
export default ToDoItem
import ToDoItem from '../todo-item/ToDoItem'
import { useDispatch, useSelector } from 'react-redux'
import { AppDispatch, RootState } from '../../redux/store'
import { removeTodo, setTodoStatus } from '../../redux/todoSlice'
import { ToDo } from '../../models/ToDo'
const TodoList = () => {
const todoList = useSelector((state: RootState) => state)
const dispatch = useDispatch<AppDispatch>()
const removeTodoItem = (id: number): void => {
dispatch(removeTodo(id))
}
const toggleTodo = (id: number): void => {
let item = todoList.filter((todo: ToDo) => todo.id === id)[0]
dispatch(setTodoStatus({ completed: !item.completed, id: item.id }))
}
return (
<div>
{todoList.map((todo: ToDo) => (
<ToDoItem
key={todo.id}
removeTodo={removeTodoItem}
toggleTodo={toggleTodo}
{...todo}
/>
))}
</div>
)
}
export default TodoList
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import React from 'react'
import ReactDOM from 'react-dom'
import { Provider } from 'react-redux'
import App from './App'
import { store } from './redux/store'
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(
//Import i18n.ts
import './translation/i18n'
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
<Provider store={store}>
<App />
</Provider>
</React.StrictMode>,
document.getElementById('root')
)
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
export interface ToDo {
id: number
description: string
completed: boolean
}
import { configureStore } from "@reduxjs/toolkit";
import todosReducer from "./todoSlice";
export const store = configureStore({
reducer: todosReducer,
});
export type AppDispatch = typeof store.dispatch;
export type RootState = ReturnType<typeof store.getState>;
\ No newline at end of file
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
import { ToDo } from "../models/ToDo";
const initialState = [] as ToDo[];
const todoSlice = createSlice({
name: "todos",
initialState,
reducers: {
addTodo: {
reducer: (state, action: PayloadAction<ToDo>) => {
state.push(action.payload);
},
prepare: (description: string) => ({
payload: {
id: Date.now(),
description,
completed: false,
} as ToDo,
}),
},
removeTodo(state, action: PayloadAction<number>) {
const index = state.findIndex((todo) => todo.id === action.payload);
state.splice(index, 1);
},
setTodoStatus(
state,
action: PayloadAction<{ completed: boolean; id: number }>
) {
const index = state.findIndex((todo) => todo.id === action.payload.id);
state[index].completed = action.payload.completed;
},
},
});
export const { addTodo, removeTodo, setTodoStatus } = todoSlice.actions;
export default todoSlice.reducer;
\ No newline at end of file
{
"buttons": {
"ok": "add",
"cancel": "delete"
}
}
\ No newline at end of file
{
"title": "An exciting scientific endeavor is space flight. People can learn more than they normally could."
}
import i18next from "i18next";
import { initReactI18next } from "react-i18next";
import translationEnglish from "./english/translation.json";
import translationSpanish from "./spanish/translation.json";
import translationUkrainian from "./ukrainian/translation.json";
import buttonsEn from "./english/buttons.json";
import buttonsSp from "./spanish/buttons.json";
import buttonsUa from "./ukrainian/buttons.json";
const resources = {
en: {
home: translationEnglish,
buttons: buttonsEn,
},
es: {
home: translationSpanish,
buttons: buttonsSp,
},
ua: {
home: translationUkrainian,
buttons: buttonsUa,
},
}
i18next
.use(initReactI18next)
.init({
resources,
lng:"en", //default language
});
export default i18next;
\ No newline at end of file
{
"buttons": {
"ok": "añadir",
"cancel": "borrar"
}
}
\ No newline at end of file
{
"title": "loremv1111111111111"
}
{
"buttons": {
"ok": "додати",
"cancel": "видалити"
}
}
\ No newline at end of file
{
"title": "Привiт"
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment