mirror of
https://github.com/NginxProxyManager/nginx-proxy-manager.git
synced 2025-08-28 03:30:05 +00:00
Add formatjs/intl locale support
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -14,6 +14,7 @@ frontend/build
|
|||||||
frontend/yarn-error.log
|
frontend/yarn-error.log
|
||||||
frontend/yarn.lock
|
frontend/yarn.lock
|
||||||
frontend/.npmrc
|
frontend/.npmrc
|
||||||
|
frontend/src/locale/lang
|
||||||
test/cypress/fixtures/example.json
|
test/cypress/fixtures/example.json
|
||||||
.vscode
|
.vscode
|
||||||
docker-build
|
docker-build
|
||||||
|
@@ -1,56 +1,69 @@
|
|||||||
version: '2'
|
version: "2"
|
||||||
|
|
||||||
tasks:
|
tasks:
|
||||||
default:
|
default:
|
||||||
cmds:
|
cmds:
|
||||||
- task: run
|
- task: run
|
||||||
|
|
||||||
run:
|
run:
|
||||||
desc: Build and run
|
desc: Build and run
|
||||||
sources:
|
sources:
|
||||||
- internal/**/*.go
|
- internal/**/*.go
|
||||||
- cmd/**/*.go
|
- cmd/**/*.go
|
||||||
cmds:
|
- ../frontend/src/locale/src/*.json
|
||||||
- task: build
|
cmds:
|
||||||
- cmd: echo -e "==> Running..."
|
- task: locale
|
||||||
silent: true
|
- task: build
|
||||||
- cmd: ../dist/bin/server
|
- cmd: echo -e "==> Running..."
|
||||||
ignore_error: true
|
silent: true
|
||||||
silent: true
|
- cmd: ../dist/bin/server
|
||||||
env:
|
ignore_error: true
|
||||||
LOG_LEVEL: debug
|
silent: true
|
||||||
|
env:
|
||||||
|
LOG_LEVEL: debug
|
||||||
|
|
||||||
build:
|
build:
|
||||||
desc: Build the server
|
desc: Build the server
|
||||||
cmds:
|
cmds:
|
||||||
- cmd: echo -e "==> Building..."
|
- cmd: echo -e "==> Building..."
|
||||||
silent: true
|
silent: true
|
||||||
- cmd: rm -f dist/bin/*
|
- cmd: rm -f dist/bin/*
|
||||||
silent: true
|
silent: true
|
||||||
- cmd: go build -ldflags="-X main.commit={{.GIT_COMMIT}} -X main.version={{.VERSION}}" -o ../dist/bin/server ./cmd/server/main.go
|
- cmd: go build -ldflags="-X main.commit={{.GIT_COMMIT}} -X main.version={{.VERSION}}" -o ../dist/bin/server ./cmd/server/main.go
|
||||||
silent: true
|
silent: true
|
||||||
- task: lint
|
- task: lint
|
||||||
vars:
|
vars:
|
||||||
GIT_COMMIT:
|
GIT_COMMIT:
|
||||||
sh: git log -n 1 --format=%h
|
sh: git log -n 1 --format=%h
|
||||||
VERSION:
|
VERSION:
|
||||||
sh: cat ../.version
|
sh: cat ../.version
|
||||||
env:
|
env:
|
||||||
GO111MODULE: on
|
GO111MODULE: on
|
||||||
CGO_ENABLED: 1
|
CGO_ENABLED: 1
|
||||||
|
|
||||||
lint:
|
lint:
|
||||||
desc: Linting
|
desc: Linting
|
||||||
cmds:
|
cmds:
|
||||||
- cmd: echo -e "==> Linting..."
|
- cmd: echo -e "==> Linting..."
|
||||||
silent: true
|
silent: true
|
||||||
- cmd: bash scripts/lint.sh
|
- cmd: bash scripts/lint.sh
|
||||||
silent: true
|
silent: true
|
||||||
|
|
||||||
test:
|
test:
|
||||||
desc: Testing
|
desc: Testing
|
||||||
cmds:
|
cmds:
|
||||||
- cmd: echo -e "==> Testing..."
|
- cmd: echo -e "==> Testing..."
|
||||||
silent: true
|
silent: true
|
||||||
- cmd: bash scripts/test.sh
|
- cmd: bash scripts/test.sh
|
||||||
silent: true
|
silent: true
|
||||||
|
|
||||||
|
locale:
|
||||||
|
desc: Locale
|
||||||
|
dir: /app/frontend
|
||||||
|
cmds:
|
||||||
|
- cmd: yarn locale-compile
|
||||||
|
silent: true
|
||||||
|
ignore_error: true
|
||||||
|
- cmd: chown -R "$PUID:$PGID" src/locale/lang
|
||||||
|
silent: true
|
||||||
|
ignore_error: true
|
||||||
|
@@ -39,9 +39,10 @@
|
|||||||
"node-sass": "^5.0.0",
|
"node-sass": "^5.0.0",
|
||||||
"prettier": "2.3.2",
|
"prettier": "2.3.2",
|
||||||
"query-string": "7.0.1",
|
"query-string": "7.0.1",
|
||||||
"react": "17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-async": "10.0.1",
|
"react-async": "10.0.1",
|
||||||
"react-dom": "17.0.2",
|
"react-dom": "17.0.2",
|
||||||
|
"react-intl": "^5.20.6",
|
||||||
"react-router-dom": "^5.2.0",
|
"react-router-dom": "^5.2.0",
|
||||||
"react-scripts": "4.0.3",
|
"react-scripts": "4.0.3",
|
||||||
"rooks": "5.0.2",
|
"rooks": "5.0.2",
|
||||||
@@ -60,7 +61,9 @@
|
|||||||
"eject": "react-scripts eject",
|
"eject": "react-scripts eject",
|
||||||
"prettier": "prettier \"**/*.+(js|json|yml|css|ts|tsx)\"",
|
"prettier": "prettier \"**/*.+(js|json|yml|css|ts|tsx)\"",
|
||||||
"format": "yarn prettier -- --write",
|
"format": "yarn prettier -- --write",
|
||||||
"lint:fix": "eslint --fix --ext .ts --ext .tsx ."
|
"lint:fix": "eslint --fix --ext .ts --ext .tsx .",
|
||||||
|
"locale-extract": "formatjs extract 'src/**/*.tsx' --out-file src/locale/src/en.json",
|
||||||
|
"locale-compile": "formatjs compile-folder src/locale/src src/locale/lang --ast"
|
||||||
},
|
},
|
||||||
"browserslist": {
|
"browserslist": {
|
||||||
"production": [
|
"production": [
|
||||||
@@ -88,5 +91,8 @@
|
|||||||
"statements": 0
|
"statements": 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@formatjs/cli": "^4.2.29"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -2,14 +2,18 @@ import React from "react";
|
|||||||
|
|
||||||
import Router from "components/Router";
|
import Router from "components/Router";
|
||||||
import { AuthProvider, HealthProvider } from "context";
|
import { AuthProvider, HealthProvider } from "context";
|
||||||
|
import { intl } from "locale";
|
||||||
|
import { RawIntlProvider } from "react-intl";
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
return (
|
return (
|
||||||
<HealthProvider>
|
<RawIntlProvider value={intl}>
|
||||||
<AuthProvider>
|
<HealthProvider>
|
||||||
<Router />
|
<AuthProvider>
|
||||||
</AuthProvider>
|
<Router />
|
||||||
</HealthProvider>
|
</AuthProvider>
|
||||||
|
</HealthProvider>
|
||||||
|
</RawIntlProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
37
frontend/src/locale/IntlProvider.tsx
Normal file
37
frontend/src/locale/IntlProvider.tsx
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import { createIntl, createIntlCache } from "react-intl";
|
||||||
|
|
||||||
|
import langEn from "./lang/en.json";
|
||||||
|
|
||||||
|
// todo
|
||||||
|
/*
|
||||||
|
const messages: Record<string, Record<string, string>> = {
|
||||||
|
"en-US": { selectalanguage: "Select a language" },
|
||||||
|
"pt-BR": { selectalanguage: "Selecione uma linguagem" },
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
// end todo
|
||||||
|
|
||||||
|
const loadMessages = (locale: string) => {
|
||||||
|
switch (locale) {
|
||||||
|
/*
|
||||||
|
case 'fr':
|
||||||
|
return import("./lang/fr.json");
|
||||||
|
*/
|
||||||
|
default:
|
||||||
|
return langEn;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const initialLocale = "en-US";
|
||||||
|
export const cache = createIntlCache();
|
||||||
|
|
||||||
|
const initialMessages = loadMessages(initialLocale);
|
||||||
|
|
||||||
|
console.log("MESSAGES:", initialMessages);
|
||||||
|
export const intl = createIntl(
|
||||||
|
// @ts-ignore messages file typings are correct
|
||||||
|
{ locale: initialLocale, messages: initialMessages },
|
||||||
|
cache,
|
||||||
|
);
|
||||||
|
|
||||||
|
export const fmt = intl.formatMessage;
|
1
frontend/src/locale/index.ts
Normal file
1
frontend/src/locale/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from "./IntlProvider";
|
20
frontend/src/locale/src/en.json
Normal file
20
frontend/src/locale/src/en.json
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"setup.create": {
|
||||||
|
"defaultMessage": "Create Account"
|
||||||
|
},
|
||||||
|
"setup.title": {
|
||||||
|
"defaultMessage": "Create your first Account"
|
||||||
|
},
|
||||||
|
"user.email": {
|
||||||
|
"defaultMessage": "Email"
|
||||||
|
},
|
||||||
|
"user.name": {
|
||||||
|
"defaultMessage": "Name"
|
||||||
|
},
|
||||||
|
"user.nickname": {
|
||||||
|
"defaultMessage": "Nickname"
|
||||||
|
},
|
||||||
|
"user.password": {
|
||||||
|
"defaultMessage": "Password"
|
||||||
|
}
|
||||||
|
}
|
@@ -3,6 +3,8 @@ import React, { useEffect, useRef, useState, ChangeEvent } from "react";
|
|||||||
import { createUser } from "api/npm";
|
import { createUser } from "api/npm";
|
||||||
import { Alert, Button } from "components";
|
import { Alert, Button } from "components";
|
||||||
import { useAuthState, useHealthState } from "context";
|
import { useAuthState, useHealthState } from "context";
|
||||||
|
import { fmt } from "locale";
|
||||||
|
import { FormattedMessage } from "react-intl";
|
||||||
|
|
||||||
import logo from "../../img/logo-text-vertical-grey.png";
|
import logo from "../../img/logo-text-vertical-grey.png";
|
||||||
|
|
||||||
@@ -81,7 +83,10 @@ function Setup() {
|
|||||||
onSubmit={onSubmit}>
|
onSubmit={onSubmit}>
|
||||||
<div className="card-body">
|
<div className="card-body">
|
||||||
<h2 className="card-title text-center mb-4">
|
<h2 className="card-title text-center mb-4">
|
||||||
Create your first Account
|
<FormattedMessage
|
||||||
|
id="setup.title"
|
||||||
|
defaultMessage="Create your first Account"
|
||||||
|
/>
|
||||||
</h2>
|
</h2>
|
||||||
{errorMessage ? (
|
{errorMessage ? (
|
||||||
<Alert type="danger" className="text-center">
|
<Alert type="danger" className="text-center">
|
||||||
@@ -90,7 +95,9 @@ function Setup() {
|
|||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label className="form-label">Name</label>
|
<label className="form-label">
|
||||||
|
<FormattedMessage id="user.name" defaultMessage="Name" />
|
||||||
|
</label>
|
||||||
<input
|
<input
|
||||||
ref={nameRef}
|
ref={nameRef}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
@@ -98,24 +105,34 @@ function Setup() {
|
|||||||
name="name"
|
name="name"
|
||||||
value={formData.name}
|
value={formData.name}
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
placeholder="Name"
|
placeholder={fmt({ id: "user.name", defaultMessage: "Name" })}
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label className="form-label">Nickname</label>
|
<label className="form-label">
|
||||||
|
<FormattedMessage
|
||||||
|
id="user.nickname"
|
||||||
|
defaultMessage="Nickname"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
<input
|
<input
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
className="form-control"
|
className="form-control"
|
||||||
name="nickname"
|
name="nickname"
|
||||||
value={formData.nickname}
|
value={formData.nickname}
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
placeholder="Nickname"
|
placeholder={fmt({
|
||||||
|
id: "user.nickname",
|
||||||
|
defaultMessage: "Nickname",
|
||||||
|
})}
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label className="form-label">Email</label>
|
<label className="form-label">
|
||||||
|
<FormattedMessage id="user.email" defaultMessage="Email" />
|
||||||
|
</label>
|
||||||
<input
|
<input
|
||||||
type="email"
|
type="email"
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
@@ -123,13 +140,21 @@ function Setup() {
|
|||||||
name="email"
|
name="email"
|
||||||
value={formData.email}
|
value={formData.email}
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
placeholder="Email"
|
placeholder={fmt({
|
||||||
|
id: "user.email",
|
||||||
|
defaultMessage: "Email",
|
||||||
|
})}
|
||||||
maxLength={150}
|
maxLength={150}
|
||||||
required
|
required
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label className="form-label">Password</label>
|
<label className="form-label">
|
||||||
|
<FormattedMessage
|
||||||
|
id="user.password"
|
||||||
|
defaultMessage="Password"
|
||||||
|
/>
|
||||||
|
</label>
|
||||||
<input
|
<input
|
||||||
type="password"
|
type="password"
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
@@ -137,7 +162,10 @@ function Setup() {
|
|||||||
name="password"
|
name="password"
|
||||||
value={formData.password}
|
value={formData.password}
|
||||||
disabled={loading}
|
disabled={loading}
|
||||||
placeholder="Password"
|
placeholder={fmt({
|
||||||
|
id: "user.password",
|
||||||
|
defaultMessage: "Password",
|
||||||
|
})}
|
||||||
minLength={8}
|
minLength={8}
|
||||||
maxLength={100}
|
maxLength={100}
|
||||||
autoComplete="off"
|
autoComplete="off"
|
||||||
@@ -146,7 +174,10 @@ function Setup() {
|
|||||||
</div>
|
</div>
|
||||||
<div className="form-footer">
|
<div className="form-footer">
|
||||||
<Button color="cyan" loading={loading} className="w-100">
|
<Button color="cyan" loading={loading} className="w-100">
|
||||||
Create Account
|
<FormattedMessage
|
||||||
|
id="setup.create"
|
||||||
|
defaultMessage="Create Account"
|
||||||
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@@ -13,8 +13,12 @@ docker_cmd() {
|
|||||||
cd "${DIR}/../.." || exit 1
|
cd "${DIR}/../.." || exit 1
|
||||||
echo -e "${BLUE}❯ ${CYAN}Installing Frontend deps ...${RESET}"
|
echo -e "${BLUE}❯ ${CYAN}Installing Frontend deps ...${RESET}"
|
||||||
rm -rf frontend/node_modules
|
rm -rf frontend/node_modules
|
||||||
|
|
||||||
docker_cmd yarn install
|
docker_cmd yarn install
|
||||||
|
|
||||||
|
echo -e "${BLUE}❯ ${CYAN}Compiling locales ...${RESET}"
|
||||||
|
docker_cmd yarn locale-compile
|
||||||
|
docker_cmd chown -R "$(id -u):$(id -g)" /app/frontend/src/locale/lang
|
||||||
|
|
||||||
echo -e "${BLUE}❯ ${CYAN}Running eslint ...${RESET}"
|
echo -e "${BLUE}❯ ${CYAN}Running eslint ...${RESET}"
|
||||||
docker_cmd yarn eslint src
|
docker_cmd yarn eslint src
|
||||||
docker_cmd yarn eslint -f junit src -o eslint.xml
|
docker_cmd yarn eslint -f junit src -o eslint.xml
|
||||||
|
Reference in New Issue
Block a user