mirror of
https://github.com/lightninglabs/lightning-terminal.git
synced 2026-08-13 12:33:36 +02:00
feat: add multi-language support
This commit is contained in:
parent
e91596930e
commit
056f784689
8 changed files with 130 additions and 6 deletions
|
|
@ -15,10 +15,13 @@
|
|||
"proxy": "https://localhost:8443",
|
||||
"dependencies": {
|
||||
"@improbable-eng/grpc-web": "0.12.0",
|
||||
"i18next": "19.4.1",
|
||||
"i18next-browser-languagedetector": "4.0.2",
|
||||
"mobx": "5.15.4",
|
||||
"mobx-react": "6.2.2",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1",
|
||||
"react-i18next": "11.3.4",
|
||||
"react-scripts": "3.4.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
@ -48,6 +51,7 @@
|
|||
"src/**/*.{js,jsx,ts,tsx}",
|
||||
"!src/**/*.d.ts",
|
||||
"!src/types/**/*.{js,ts}",
|
||||
"!src/i18n/**/*.{js,ts}",
|
||||
"!src/index.tsx"
|
||||
]
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
import React, { useEffect } from 'react';
|
||||
import { observer } from 'mobx-react';
|
||||
import './App.css';
|
||||
import usePrefixedTranslation from 'hooks/usePrefixedTranslation';
|
||||
import { channel, node, swap } from 'action';
|
||||
import store from 'store';
|
||||
|
||||
const App = () => {
|
||||
const { l } = usePrefixedTranslation('App');
|
||||
useEffect(() => {
|
||||
// fetch node info when the component is mounted
|
||||
const fetchInfo = async () => await node.getInfo();
|
||||
|
|
@ -13,25 +15,25 @@ const App = () => {
|
|||
|
||||
return (
|
||||
<div className="App">
|
||||
<p>Node Info</p>
|
||||
<p>{l('App.nodeInfo')}</p>
|
||||
{store.info && (
|
||||
<>
|
||||
<table className="App-table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>Pubkey</th>
|
||||
<th>{l('pubkey')}</th>
|
||||
<td>{store.info.identityPubkey}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Alias</th>
|
||||
<th>{l('alias')}</th>
|
||||
<td>{store.info.alias}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Version</th>
|
||||
<th>{l('version')}</th>
|
||||
<td>{store.info.version}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th># Channels</th>
|
||||
<th>{l('numChannels')}</th>
|
||||
<td>{store.info.numActiveChannels}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
|
|
|||
24
app/src/hooks/usePrefixedTranslation.ts
Normal file
24
app/src/hooks/usePrefixedTranslation.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
import { useCallback } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
/**
|
||||
* A hook which returns a `t` function that inserts a prefix in each key lookup
|
||||
* @param prefix the prefix to use for all translation keys
|
||||
*/
|
||||
const usePrefixedTranslation = (prefix: string) => {
|
||||
const { t } = useTranslation();
|
||||
// the new `t` function that will append the prefix
|
||||
const translate = useCallback(
|
||||
(key: string, options?: string | object) => {
|
||||
// if the key contains a '.', then don't add the prefix
|
||||
return key.includes('.') ? t(key, options) : t(`${prefix}.${key}`, options);
|
||||
},
|
||||
[prefix, t],
|
||||
);
|
||||
|
||||
return {
|
||||
l: translate,
|
||||
};
|
||||
};
|
||||
|
||||
export default usePrefixedTranslation;
|
||||
50
app/src/i18n/index.ts
Normal file
50
app/src/i18n/index.ts
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
import { initReactI18next } from 'react-i18next';
|
||||
import i18n, { InitOptions } from 'i18next';
|
||||
import LanguageDetector from 'i18next-browser-languagedetector';
|
||||
import enUS from './locales/en-US.json';
|
||||
|
||||
const defaultLanguage = 'en-US';
|
||||
|
||||
export const languages: { [index: string]: string } = {
|
||||
'en-US': 'English',
|
||||
};
|
||||
|
||||
/**
|
||||
* create a mapping of locales -> translations
|
||||
*/
|
||||
const resources = Object.keys(languages).reduce((acc: { [key: string]: any }, lang) => {
|
||||
switch (lang) {
|
||||
case 'en-US':
|
||||
acc[lang] = { translation: enUS };
|
||||
break;
|
||||
}
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
/**
|
||||
* create an array of allowed languages
|
||||
*/
|
||||
const whitelist = Object.keys(languages).reduce((acc: string[], lang) => {
|
||||
acc.push(lang);
|
||||
|
||||
if (lang.includes('-')) {
|
||||
acc.push(lang.substring(0, lang.indexOf('-')));
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
|
||||
const config: InitOptions = {
|
||||
lng: defaultLanguage,
|
||||
resources,
|
||||
whitelist,
|
||||
fallbackLng: defaultLanguage,
|
||||
keySeparator: false,
|
||||
interpolation: {
|
||||
escapeValue: false,
|
||||
},
|
||||
};
|
||||
|
||||
i18n.use(LanguageDetector).use(initReactI18next).init(config);
|
||||
|
||||
export default i18n;
|
||||
7
app/src/i18n/locales/en-US.json
Normal file
7
app/src/i18n/locales/en-US.json
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"App.nodeInfo": "Node Info",
|
||||
"App.pubkey": "Pubkey",
|
||||
"App.alias": "Alias",
|
||||
"App.version": "Version",
|
||||
"App.numChannels": "# Channels"
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import 'mobx-react/batchingForReactDom';
|
||||
import './i18n';
|
||||
import './index.css';
|
||||
import App from './App';
|
||||
|
||||
|
|
|
|||
|
|
@ -5,3 +5,5 @@ import 'mobx-react-lite/batchingForReactDom';
|
|||
// expect(element).toHaveTextContent(/react/i)
|
||||
// learn more: https://github.com/testing-library/jest-dom
|
||||
import '@testing-library/jest-dom/extend-expect';
|
||||
// enable i18n translations in unit tests
|
||||
import './i18n';
|
||||
|
|
|
|||
|
|
@ -899,7 +899,7 @@
|
|||
dependencies:
|
||||
regenerator-runtime "^0.13.4"
|
||||
|
||||
"@babel/runtime@^7.0.0", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.1", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.4", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7":
|
||||
"@babel/runtime@^7.0.0", "@babel/runtime@^7.3.1", "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.1", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.7.4", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7":
|
||||
version "7.9.2"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.9.2.tgz#d90df0583a3a252f09aaa619665367bae518db06"
|
||||
integrity sha512-NE2DtOdufG7R5vnfQUTehdTfNycfUANEtCa9PssN9O/xmTzP4E08UI797ixaei6hBEVL9BI/PsdJS5x7mWoB9Q==
|
||||
|
|
@ -5003,6 +5003,13 @@ html-minifier-terser@^5.0.1:
|
|||
relateurl "^0.2.7"
|
||||
terser "^4.6.3"
|
||||
|
||||
html-parse-stringify2@2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/html-parse-stringify2/-/html-parse-stringify2-2.0.1.tgz#dc5670b7292ca158b7bc916c9a6735ac8872834a"
|
||||
integrity sha1-3FZwtyksoVi3vJFsmmc1rIhyg0o=
|
||||
dependencies:
|
||||
void-elements "^2.0.1"
|
||||
|
||||
html-webpack-plugin@4.0.0-beta.11:
|
||||
version "4.0.0-beta.11"
|
||||
resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-4.0.0-beta.11.tgz#3059a69144b5aecef97708196ca32f9e68677715"
|
||||
|
|
@ -5102,6 +5109,20 @@ https-browserify@^1.0.0:
|
|||
resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
|
||||
integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=
|
||||
|
||||
i18next-browser-languagedetector@4.0.2:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/i18next-browser-languagedetector/-/i18next-browser-languagedetector-4.0.2.tgz#eb02535cc5e57dd534fc60abeede05a3823a8551"
|
||||
integrity sha512-AK4IZ3XST4HIKShgpB2gOFeDPrMOnZx56GLA6dGo/8rvkiczIlq05lV8w77c3ShEZxtTZeUVRI4Q/cBFFVXS/w==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.5.5"
|
||||
|
||||
i18next@19.4.1:
|
||||
version "19.4.1"
|
||||
resolved "https://registry.yarnpkg.com/i18next/-/i18next-19.4.1.tgz#4929d15d3d01e4712350a368d005cefa50ff5455"
|
||||
integrity sha512-dC3ue15jkLebN2je4xEjfjVYd/fSAo+UVK9f+JxvceCJRowkI+S0lGohgKejqU+FYLfvw9IAPylIIEWwR8Djrg==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.3.1"
|
||||
|
||||
iconv-lite@0.4.24, iconv-lite@^0.4.24:
|
||||
version "0.4.24"
|
||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
|
||||
|
|
@ -8572,6 +8593,14 @@ react-error-overlay@^6.0.7:
|
|||
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.7.tgz#1dcfb459ab671d53f660a991513cb2f0a0553108"
|
||||
integrity sha512-TAv1KJFh3RhqxNvhzxj6LeT5NWklP6rDr2a0jaTfsZ5wSZWHOGeqQyejUp3xxLfPt2UpyJEcVQB/zyPcmonNFA==
|
||||
|
||||
react-i18next@11.3.4:
|
||||
version "11.3.4"
|
||||
resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-11.3.4.tgz#355df5fe5133e5e30302d166f529678100ffc968"
|
||||
integrity sha512-IRZMD7PAM3C+fJNzRbyLNi1ZD0kc3Z3obBspJjEl+9H+ME41PhVor3BpdIqv/Rm7lUoGhMjmpu42J45ooJ61KA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.3.1"
|
||||
html-parse-stringify2 "2.0.1"
|
||||
|
||||
react-is@^16.12.0, react-is@^16.8.1, react-is@^16.8.4:
|
||||
version "16.13.1"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
||||
|
|
@ -10353,6 +10382,11 @@ vm-browserify@^1.0.1:
|
|||
resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.2.tgz#78641c488b8e6ca91a75f511e7a3b32a86e5dda0"
|
||||
integrity sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==
|
||||
|
||||
void-elements@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-2.0.1.tgz#c066afb582bb1cb4128d60ea92392e94d5e9dbec"
|
||||
integrity sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=
|
||||
|
||||
w3c-hr-time@^1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue