base for translating the webapp

This commit is contained in:
Light-Wing 2023-06-15 16:55:12 -04:00
parent f544d74c55
commit 8d8258cc9f
16 changed files with 12191 additions and 11094 deletions

10
lingui.config.js Normal file
View File

@ -0,0 +1,10 @@
/** @type {import('@lingui/conf').LinguiConfig} */
module.exports = {
locales: ["en", "ch"],
sourceLocale: "ch",
catalogs: [{
path: "src/locales/{locale}/messages",
include: ["src"]
}],
format: "po"
}

23009
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -3,29 +3,34 @@
"version": "0.1.0", "version": "0.1.0",
"private": true, "private": true,
"dependencies": { "dependencies": {
"@babel/runtime": "^7.22.5",
"@lingui/core": "^4.2.1",
"@lingui/react": "^4.2.1",
"@testing-library/jest-dom": "^4.2.4", "@testing-library/jest-dom": "^4.2.4",
"@testing-library/react": "^9.3.2", "@testing-library/react": "^9.3.2",
"@testing-library/user-event": "^7.1.2", "@testing-library/user-event": "^7.1.2",
"jsqr": "^1.3.1", "jsqr": "^1.4.0",
"medium-zoom": "^1.0.5", "medium-zoom": "^1.0.8",
"prop-types": "^15.7.2", "prop-types": "^15.8.1",
"react": "^16.13.1", "react": "^16.14.0",
"react-color": "^2.18.1", "react-color": "^2.19.3",
"react-dom": "^16.13.1", "react-dom": "^16.14.0",
"react-ga": "^3.0.0", "react-ga": "^3.3.1",
"react-github-btn": "^1.2.0", "react-github-btn": "^1.4.0",
"react-indiana-drag-scroll": "^1.6.1", "react-indiana-drag-scroll": "^1.8.1",
"react-lazy-load": "^3.0.13", "react-lazy-load": "^3.1.14",
"react-redux": "^7.2.0", "react-redux": "^7.2.9",
"react-scripts": "3.4.1", "react-scripts": "5.0.1",
"redux": "^4.0.5", "redux": "^4.2.1",
"serialize-javascript": "^3.1.0" "serialize-javascript": "^3.1.0"
}, },
"scripts": { "scripts": {
"start": "react-scripts start", "start": "react-scripts start",
"build": "react-scripts build", "build": "react-scripts build",
"test": "react-scripts test", "test": "react-scripts test",
"eject": "react-scripts eject" "eject": "react-scripts eject",
"extract": "lingui extract",
"compile": "lingui compile"
}, },
"eslintConfig": { "eslintConfig": {
"extends": "react-app" "extends": "react-app"
@ -44,8 +49,10 @@
}, },
"homepage": "./", "homepage": "./",
"devDependencies": { "devDependencies": {
"@lingui/cli": "^4.2.1",
"@lingui/macro": "^4.2.1",
"reactcss": "^1.2.3", "reactcss": "^1.2.3",
"redux-devtools": "^3.5.0", "redux-devtools": "^3.7.0",
"tcb-js-sdk": "^1.6.1" "tcb-js-sdk": "^1.10.10"
} }
} }

View File

@ -13,6 +13,19 @@ import {loadDownloadData} from "../../actions";
import ReactGA from 'react-ga'; import ReactGA from 'react-ga';
import {setScrollbarWidthProp} from "../../utils/util" import {setScrollbarWidthProp} from "../../utils/util"
import { i18n } from '@lingui/core'
import { I18nProvider } from '@lingui/react'
import { messages as enMessages } from '../../locales/en/messages'
import { messages as chMessages } from '../../locales/ch/messages'
import LanguageSwitcher from './langSwitcher';
i18n.load({
en: enMessages,
ch: chMessages,
})
i18n.activate('en')
ReactGA.initialize('UA-165845289-1'); ReactGA.initialize('UA-165845289-1');
ReactGA.addTrackers( ReactGA.addTrackers(
@ -52,12 +65,15 @@ function App({ dispatch }) {
<header className="App-header"> <header className="App-header">
<div className="Layout"> <div className="Layout">
<div className="Qr-outer"> <div className="Qr-outer">
<PartHeader/> <I18nProvider i18n={i18n}>
<PartStylesViewer/> <LanguageSwitcher />
<PartParams/> <PartHeader />
<PartDownloadViewer updateDownloadData={updateDownloadData}/> <PartStylesViewer />
<PartMore/> <PartParams />
<PartFooter/> <PartDownloadViewer updateDownloadData={updateDownloadData} />
<PartMore />
<PartFooter />
</I18nProvider>
</div> </div>
</div> </div>
</header> </header>

View File

@ -2,6 +2,7 @@ import React, {useState} from 'react';
import './App.css'; import './App.css';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import {isWeiXin} from "../../utils/navigatorUtils"; import {isWeiXin} from "../../utils/navigatorUtils";
import { Trans } from '@lingui/react';
const CountComponent = ({ value }) => { const CountComponent = ({ value }) => {
if (isNaN(value)) return null; if (isNaN(value)) return null;
@ -13,8 +14,7 @@ const WxMessage = () => {
if (isWeiXin()) { if (isWeiXin()) {
return ( return (
<div className="note-font" id="wx-message-inner"> <div className="note-font" id="wx-message-inner">
当前客户端不支持下载 SVG<br /> <Trans id='WxMessage'>当前客户端不支持下载 SVG,<br /> 请下载 JPG 并长按二维码保存</Trans>
请下载 JPG 并长按二维码保存
</div> </div>
) )
} }
@ -42,7 +42,10 @@ const PartDownload = ({ value, downloadCount, onSvgDownload, onImgDownload }) =>
<div className="Qr-Centered title-margin"> <div className="Qr-Centered title-margin">
<div className="Qr-s-title">Downloads</div> <div className="Qr-s-title">Downloads</div>
<p className="Qr-s-subtitle"> <p className="Qr-s-subtitle">
<span>下载二维码 {value}</span> <span>
<Trans id='下载二维码 — '>下载二维码 </Trans>
{value}
</span>
<CountComponent value={downloadCount} /> <CountComponent value={downloadCount} />
</p> </p>
</div> </div>

View File

@ -2,13 +2,18 @@ import React from "react";
import '../Qrcode.css'; import '../Qrcode.css';
import InputText from "../../containers/app/InputText"; import InputText from "../../containers/app/InputText";
import QrbtfLogo from "../svg/QrbtfLogo"; import QrbtfLogo from "../svg/QrbtfLogo";
import { Trans } from '@lingui/macro';
const PartHeader = () => ( const PartHeader = () => (
<div className="Qr-Centered"> <div className="Qr-Centered">
<div> <div>
<h1 className="Qr-title"><QrbtfLogo className="Qr-title-svg" /></h1> <h1 className="Qr-title"><QrbtfLogo className="Qr-title-svg" /></h1>
</div> </div>
<p className="Qr-subtitle">参数化二维码生成器{/* <sup className="Gray">测试版</sup>*/}</p> <p className="Qr-subtitle">
<Trans id="PartHeader">
参数化二维码生成器
</Trans>
{/* <sup className="Gray">测试版</sup>*/}</p>
<InputText/> <InputText/>
</div> </div>
) )

View File

@ -9,7 +9,7 @@ import ImageZoom from "../../containers/app/ImageZoom";
import LinkTrace from "../link/LinkTrace"; import LinkTrace from "../link/LinkTrace";
import {isPC} from "../../utils/navigatorUtils"; import {isPC} from "../../utils/navigatorUtils";
import {handleScroll} from "../../utils/gaHelper"; import {handleScroll} from "../../utils/gaHelper";
import { Trans } from "@lingui/macro"
const pictures = [ const pictures = [
'https://7172-qrbtf-1d845d-1255694434.tcb.qcloud.la/QrbtfGallery/gallery04.jpg', 'https://7172-qrbtf-1d845d-1255694434.tcb.qcloud.la/QrbtfGallery/gallery04.jpg',
'https://7172-qrbtf-1d845d-1255694434.tcb.qcloud.la/QrbtfGallery/gallery02.jpg', 'https://7172-qrbtf-1d845d-1255694434.tcb.qcloud.la/QrbtfGallery/gallery02.jpg',
@ -24,11 +24,14 @@ const PartMore = () => {
return ( return (
<div className="Qr-titled-nobg"> <div className="Qr-titled-nobg">
<div className="Qr-Centered title-margin"> <div className="Qr-Centered title-margin">
<Trans >
<div className="Qr-s-title">More</div> <div className="Qr-s-title">More</div>
<p className="Qr-s-subtitle">更多</p> <p className="Qr-s-subtitle">更多</p>
<div className="Qr-s-subtitle Qr-rel"> <div className="Qr-s-subtitle Qr-rel">
{isPC() ? <div className="Qr-style-hint">拖拽滑动</div> : null} {isPC() ? <div className="Qr-style-hint">拖拽滑动</div> : null}
</div> </div>
</Trans>
</div> </div>
<div className="title-margin"> <div className="title-margin">
<div className="Qr-article"> <div className="Qr-article">
@ -37,7 +40,10 @@ const PartMore = () => {
data-color-scheme="no-preference: light; light: light; dark: dark;" data-color-scheme="no-preference: light; light: light; dark: dark;"
data-icon="octicon-star" data-size="large" data-show-count="true" data-icon="octicon-star" data-size="large" data-show-count="true"
aria-label="Star ciaochaos/qrbtf on GitHub">Star</GitHubButton></p> aria-label="Star ciaochaos/qrbtf on GitHub">Star</GitHubButton></p>
<h2>设计分享</h2> <h2><Trans>
设计分享
</Trans>
</h2>
</div> </div>
<ScrollContainer <ScrollContainer
className="Qr-s Qr-s-gallery" className="Qr-s Qr-s-gallery"

View File

@ -3,12 +3,16 @@ import './App.css';
import ParamListViewer from "../../containers/param/ParamListViewer"; import ParamListViewer from "../../containers/param/ParamListViewer";
import ParamCorrectLevelViewer from "../../containers/param/ParamCorrectLevelViewer"; import ParamCorrectLevelViewer from "../../containers/param/ParamCorrectLevelViewer";
import ParamIconViewer from "../../containers/param/disposable/ParamIconViewer"; import ParamIconViewer from "../../containers/param/disposable/ParamIconViewer";
import { Trans } from '@lingui/macro';
const PartParams = () => ( const PartParams = () => (
<div className="Qr-titled-nobg"> <div className="Qr-titled-nobg">
<div className="Qr-Centered title-margin"> <div className="Qr-Centered title-margin">
<div className="Qr-s-title">Parameters</div> <div className="Qr-s-title">Parameters</div>
<p className="Qr-s-subtitle">参数调整</p> <p className="Qr-s-subtitle"><Trans>
参数调整
</Trans>
</p>
</div> </div>
<div className="Qr-Centered"> <div className="Qr-Centered">
<div className="Qr-div-table"> <div className="Qr-div-table">

View File

@ -0,0 +1,26 @@
import React from 'react';
import { useLingui } from '@lingui/react';
import { Trans } from '@lingui/macro';
const LanguageSwitcher = () => {
const { i18n } = useLingui();
const handleLanguageChange = (event) => {
const selectedLanguage = event.target.value;
i18n.activate(selectedLanguage);
};
return (
<div>
<label htmlFor="language-select">
<Trans>Select Language:</Trans>
</label>
<select id="language-select" onChange={handleLanguageChange}>
<option value="en">English</option>
<option value="ch">Chinese</option>
</select>
</div>
);
};
export default LanguageSwitcher;

View File

@ -35,11 +35,11 @@ let defaultDrawIcon = function ({ qrcode, params, title, icon }) {
if (icon && iconEnabled) { if (icon && iconEnabled) {
const randomIdDefs = getIdNum(); const randomIdDefs = getIdNum();
const randomIdClips = getIdNum(); const randomIdClips = getIdNum();
pointList.push(<path d={sq25} stroke="#FFF" strokeWidth={100/iconSize * 1} fill="#FFF" transform={'translate('+String(iconXY)+','+String(iconXY)+') ' + 'scale(' + String(iconSize/100) + ',' + String(iconSize/100) + ')'} />); pointList.push(<path d={sq25} stroke="#FFF" strokeWidth={100 / iconSize * 1} fill="#FFF" transform={'translate(' + String(iconXY) + ',' + String(iconXY) + ') scale(' + String(iconSize / 100) + ',' + String(iconSize / 100) + ')'} />);
pointList.push( pointList.push(
<g key={id++}> <g key={id++}>
<defs> <defs>
<path id={"defs-path" + randomIdDefs} d={sq25} fill="#FFF" transform={'translate('+String(iconXY)+','+String(iconXY)+') ' + 'scale(' + String(iconSize/100) + ',' + String(iconSize/100) + ')'} /> </defs> <path id={"defs-path" + randomIdDefs} d={sq25} fill="#FFF" transform={'translate(' + String(iconXY) + ',' + String(iconXY) + ') scale(' + String(iconSize / 100) + ',' + String(iconSize / 100) + ')'} /> </defs>
<clipPath id={"clip-path" + randomIdClips}> <clipPath id={"clip-path" + randomIdClips}>
<use xlinkHref={"#defs-path" + randomIdDefs} overflow="visible"/> <use xlinkHref={"#defs-path" + randomIdDefs} overflow="visible"/>
</clipPath> </clipPath>
@ -115,16 +115,16 @@ let builtinDrawIcon = function ({ qrcode, params, title, icon }) {
if (icon && iconMode) { if (icon && iconMode) {
const randomIdDefs = getIdNum(); const randomIdDefs = getIdNum();
const randomIdClips = getIdNum(); const randomIdClips = getIdNum();
pointList.push(<path d={sq25} stroke="#FFF" strokeWidth={100/iconSize * 1} fill="#FFF" transform={'translate('+String(iconXY)+','+String(iconXY)+') ' + 'scale(' + String(iconSize/100) + ',' + String(iconSize/100) + ')'} />); pointList.push(<path d={sq25} stroke="#FFF" strokeWidth={100 / iconSize * 1} fill="#FFF" transform={'translate(' + String(iconXY) + ',' + String(iconXY) + ') scale(' + String(iconSize / 100) + ',' + String(iconSize / 100) + ')'} />);
pointList.push( pointList.push(
<g key={id++}> <g key={id++}>
<defs> <defs>
<path id={"defs-path" + randomIdDefs} d={sq25} fill="#FFF" transform={'translate('+String(iconXY)+','+String(iconXY)+') ' + 'scale(' + String(iconSize/100) + ',' + String(iconSize/100) + ')'} /> </defs> <path id={"defs-path" + randomIdDefs} d={sq25} fill="#FFF" transform={'translate(' + String(iconXY) + ',' + String(iconXY) + ') scale(' + String(iconSize / 100) + ',' + String(iconSize / 100) + ')'} /> </defs>
<clipPath id={"clip-path" + randomIdClips}> <clipPath id={"clip-path" + randomIdClips}>
<use xlinkHref={"#defs-path" + randomIdDefs} overflow="visible"/> <use xlinkHref={"#defs-path" + randomIdDefs} overflow="visible"/>
</clipPath> </clipPath>
<g clipPath={"url(#clip-path" + randomIdClips + ")"}> <g clipPath={"url(#clip-path" + randomIdClips + ")"}>
<g transform={'translate('+String(iconXY)+','+String(iconXY)+') ' + 'scale(' + String(iconSize/100) + ',' + String(iconSize/100) + ')'} > <g transform={'translate(' + String(iconXY) + ',' + String(iconXY) + ') scale(' + String(iconSize / 100) + ',' + String(iconSize / 100) + ')'} >
{builtinIcon()} {builtinIcon()}
</g> </g>
</g> </g>

View File

@ -4,6 +4,7 @@ import React, {useRef} from "react";
import {isPicture} from "../../utils/imageUtils"; import {isPicture} from "../../utils/imageUtils";
import {decodeData} from "../../utils/qrcodeHandler"; import {decodeData} from "../../utils/qrcodeHandler";
import { handleUpload, handleInputUrl } from "../../utils/gaHelper"; import { handleUpload, handleInputUrl } from "../../utils/gaHelper";
import { Trans } from '@lingui/macro';
const InputText = ({dispatch}) => { const InputText = ({dispatch}) => {
const textRef = useRef(); const textRef = useRef();
@ -67,7 +68,9 @@ const InputText = ({dispatch}) => {
/> />
</div> </div>
<div className="Qr-input-hint"> <div className="Qr-input-hint">
上传普通二维码或输入网址 <Trans>
上传普通二维码或输入网址
</Trans>
</div> </div>
</div> </div>
</React.Fragment>); </React.Fragment>);

View File

@ -0,0 +1 @@
/*eslint-disable*/module.exports={messages:JSON.parse("{\"下载二维码 — \":\"下载二维码 — \",\"WxMessage\":\"WxMessage\",\"PartDownload\":\"PartDownload\",\"PartMore1\":[\"<0>More</0><1>更多</1><2>\",[\"0\"],\"</2>\"],\"qINNCJ\":[\"<0>More</0><1>更多</1><2>\",[\"0\"],\"</2>\"],\"ChBdlP\":\"选择语言:\",\"trC0sO\":\"上传普通二维码或输入网址\",\"PartHeader\":\"参数化二维码生成器\",\"MuoWZZ\":\"参数化二维码生成器\",\"PYk7II\":\"参数调整\",\"1R0sTY\":\"设计分享\"}")};

View File

@ -0,0 +1,63 @@
msgid ""
msgstr ""
"POT-Creation-Date: 2023-06-15 15:22-0400\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: @lingui/cli\n"
"Language: ch\n"
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: \n"
"Last-Translator: \n"
"Language-Team: \n"
"Plural-Forms: \n"
#. js-lingui-explicit-id
#: src/components/app/PartDownload.js:46
msgid "下载二维码 — "
msgstr "下载二维码 — "
#. js-lingui-explicit-id
#: src/components/app/PartDownload.js:17
msgid "WxMessage"
msgstr "WxMessage"
#. js-lingui-explicit-id
#: src/components/app/PartDownload.js:45
#~ msgid "PartDownload"
#~ msgstr "PartDownload"
#. js-lingui-explicit-id
#: src/components/app/PartMore.js:27
#~ msgid "PartMore1"
#~ msgstr "<0>More</0><1>更多</1><2>{0}</2>"
#: src/components/app/PartMore.js:27
msgid "<0>More</0><1>更多</1><2>{0}</2>"
msgstr "<0>More</0><1>更多</1><2>{0}</2>"
#: src/components/app/langSwitcher.js:16
msgid "Select Language:"
msgstr "选择语言:"
#: src/containers/app/InputText.js:71
msgid "上传普通二维码或输入网址"
msgstr "上传普通二维码或输入网址"
#. js-lingui-explicit-id
#: src/components/app/PartHeader.js:13
msgid "PartHeader"
msgstr "参数化二维码生成器"
#: src/components/app/PartHeader.js:13
#~ msgid "参数化二维码生成器"
#~ msgstr "参数化二维码生成器"
#: src/components/app/PartParams.js:12
msgid "参数调整"
msgstr "参数调整"
#: src/components/app/PartMore.js:43
msgid "设计分享"
msgstr "设计分享"

View File

@ -0,0 +1 @@
/*eslint-disable*/module.exports={messages:JSON.parse("{\"下载二维码 — \":\"Download QR code —\",\"WxMessage\":\"The current client does not support downloading SVG,<br />Please download JPG and long press the QR code to save\",\"PartDownload\":\"PartDownload\",\"PartMore1\":[\"<0>More</0><1>更多</1><2>\",[\"0\"],\"</2>\"],\"qINNCJ\":[\"<0>More</0><1>More</1><2>\",[\"0\"],\"</2>\"],\"ChBdlP\":\"Select Language:\",\"trC0sO\":\"Upload a common QR code or enter a URL\",\"PartHeader\":\"Parametric QR code generator\",\"MuoWZZ\":\"Parametric QR code generator\",\"PYk7II\":\"Parameter adjustment\",\"1R0sTY\":\"design sharing\"}")};

View File

@ -0,0 +1,53 @@
msgid ""
msgstr ""
"POT-Creation-Date: 2023-06-15 15:21-0400\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: @lingui/cli\n"
"Language: en\n"
"Project-Id-Version: \n"
"Report-Msgid-Bugs-To: \n"
"PO-Revision-Date: \n"
"Last-Translator: \n"
"Language-Team: \n"
"Plural-Forms: \n"
#. js-lingui-explicit-id
#: src/components/app/PartDownload.js:46
msgid "下载二维码 — "
msgstr "Download QR code —"
#. js-lingui-explicit-id
#: src/components/app/PartDownload.js:17
msgid "WxMessage"
msgstr "The current client does not support downloading SVG,<br />Please download JPG and long press the QR code to save"
#: src/components/app/PartMore.js:27
msgid "<0>More</0><1>更多</1><2>{0}</2>"
msgstr "<0>More</0><1>More</1><2>{0}</2>"
#: src/components/app/langSwitcher.js:16
msgid "Select Language:"
msgstr "Select Language:"
#: src/containers/app/InputText.js:71
msgid "上传普通二维码或输入网址"
msgstr "Upload a common QR code or enter a URL"
#. js-lingui-explicit-id
#: src/components/app/PartHeader.js:13
msgid "PartHeader"
msgstr "Parametric QR code generator"
#: src/components/app/PartHeader.js:13
#~ msgid "参数化二维码生成器"
#~ msgstr "Parametric QR code generator"
#: src/components/app/PartParams.js:12
msgid "参数调整"
msgstr "Parameter adjustment"
#: src/components/app/PartMore.js:43
msgid "设计分享"
msgstr "design sharing"

View File

@ -0,0 +1,8 @@
msgid ""
msgstr ""
"POT-Creation-Date: 2023-06-15 15:21-0400\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=utf-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: @lingui/cli\n"
"Language: fr\n"