Skip to content

Instantly share code, notes, and snippets.

@farhanlatheef
Last active February 28, 2024 05:27
Show Gist options
  • Save farhanlatheef/e3c4b4a5123f9c4517b58538fca924bf to your computer and use it in GitHub Desktop.
Save farhanlatheef/e3c4b4a5123f9c4517b58538fca924bf to your computer and use it in GitHub Desktop.
A simple react app with multiple languages (english and spanish) with translations automatically sentence cased. For example, "Send Message" will be displayed as "Send message"
.App {
font-family: 'Arial', sans-serif;
text-align: center;
margin: 20px;
}
h1 {
color: #333;
}
p {
color: #666;
}
.message-container {
display: flex;
justify-content: space-around;
margin-top: 20px;
}
.incoming-message,
.outgoing-message {
padding: 10px;
margin: 5px;
border: 1px solid #ccc;
border-radius: 5px;
}
.incoming-message {
background-color: #f0f0f0;
}
.outgoing-message {
background-color: #e6f7ff;
}
import React from "react";
import i18nextInitializer from "./i18nextInitializer";
import en from "./en.json";
import es from "./es.json";
import { useTranslation } from "react-i18next";
import "./App.css";
import LanguageSwitch from "./LanguageSwitch";
i18nextInitializer({ en: { translation: en }, es: { translation: es } });
function App() {
const { t } = useTranslation();
return (
<div className="App">
<LanguageSwitch />
<h1>{t("app.title")}</h1>
<p>{t("app.intro")}</p>
<div className="message-container">
<div className="incoming-message">
{t("messages.incoming", { user: "John", message: "Hey there!" })}
</div>
<div className="outgoing-message">
{t("messages.outgoing", {
user: "Alice",
message: "Hi John, how are you?",
})}
</div>
</div>
</div>
);
}
export default App;
export const LOWERCASED = "__LOWERCASED__";
export const ANY_CASE = "anyCase";
import { LOWERCASED , ANY_CASE} from './constants';
/**
Formatter that lowercase all dynamic part of the text
*/
export const lowerCaseFormatter = (value, format) => {
if (!value || format === ANY_CASE || typeof value !== "string") {
return value;
}
return LOWERCASED + value.toLocaleLowerCase();
};
import { LOWERCASED } from './constants';
const sentenceCase = value =>
value.charAt(0).toLocaleUpperCase() + value.slice(1);
/**
Post processor that undo lowercasing if the dynamic part comes first.
*/
export const sentenceCaseProcessor = {
type: "postProcessor",
name: "sentenceCaseProcessor",
process: value => {
const shouldSentenceCase = value.startsWith(LOWERCASED);
value = value.replaceAll(LOWERCASED, "");
return shouldSentenceCase ? sentenceCase(value) : value;
},
};
{
"app": {
"title": "Multilingual Messaging App",
"intro": "Welcome to our multilingual messaging app! Start chatting now."
},
"messages": {
"incoming": "{{user}} sent: {{message}}",
"outgoing": "You sent to {{user, anyCase}}: {{message, anyCase}}"
}
}
{
"app": {
"title": "Aplicación de Mensajería Multilingüe",
"intro": "¡Bienvenido a nuestra aplicación de mensajería multilingüe! Comienza a chatear ahora."
},
"messages": {
"incoming": "{{user}} envió: {{message}}",
"outgoing": "Enviaste a {{user, anyCase}}: {{message, anyCase}}"
}
}
import i18n from "i18next";
import LanguageDetector from "i18next-browser-languagedetector";
import { initReactI18next } from "react-i18next";
import { lowerCaseFormatter } from './customFormatter';
import { sentenceCaseProcessor } from './customPostProcessor';
const i18nextInitializer = resources => {
i18n
.use(LanguageDetector)
.use(initReactI18next)
.use(sentenceCaseProcessor)
.init({
resources: resources,
fallbackLng: "en",
interpolation: {
escapeValue: false,
skipOnVariables: false,
alwaysFormat: true,
format: (value, format, lng, options) => {
return lowerCaseFormatter(value, format);
},
},
postProcess: [sentenceCaseProcessor.name],
detection: {
order: ["querystring", "cookie", "navigator", "path"],
caches: ["cookie"],
lookupQuerystring: "lang",
lookupCookie: "lang",
},
});
}
export default i18nextInitializer;
import React, { useState } from "react";
import { useTranslation } from "react-i18next";
function LanguageSwitch() {
const { i18n } = useTranslation();
const [currentLanguage, setCurrentLanguage] = useState("en");
const changeLanguage = (language) => {
i18n.changeLanguage(language);
setCurrentLanguage(language);
};
return (
<div className="language-switcher">
<button
onClick={() => changeLanguage("en")}
disabled={currentLanguage === "en"}
>
English
</button>
<button
onClick={() => changeLanguage("es")}
disabled={currentLanguage === "es"}
>
Español
</button>
</div>
);
}
export default LanguageSwitch;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment