Updating translations and adding a translation tracker
This commit is contained in:
@@ -32,6 +32,19 @@ services:
|
|||||||
- "traefik.http.routers.gui.rule=PathPrefix(`/`)"
|
- "traefik.http.routers.gui.rule=PathPrefix(`/`)"
|
||||||
- "traefik.http.services.gui.loadbalancer.server.port=5173"
|
- "traefik.http.services.gui.loadbalancer.server.port=5173"
|
||||||
|
|
||||||
|
i18n:
|
||||||
|
build:
|
||||||
|
context: ./i18n
|
||||||
|
restart: always
|
||||||
|
volumes:
|
||||||
|
- ./i18n/app/src:/app/src
|
||||||
|
- ./gui/rpk-gui/public:/app/public
|
||||||
|
labels:
|
||||||
|
- "traefik.enable=true"
|
||||||
|
- "traefik.http.routers.i18n.entrypoints=web"
|
||||||
|
- "traefik.http.routers.i18n.rule=PathPrefix(`/locales/add`)"
|
||||||
|
- "traefik.http.services.i18n.loadbalancer.server.port=8100"
|
||||||
|
|
||||||
proxy:
|
proxy:
|
||||||
image: traefik:latest
|
image: traefik:latest
|
||||||
restart: always
|
restart: always
|
||||||
|
|||||||
@@ -73,8 +73,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
"info": "You may have forgotten to add the {{action}} component to {{resource}} resource.",
|
|
||||||
"404": "Sorry, the page you visited does not exist.",
|
"404": "Sorry, the page you visited does not exist.",
|
||||||
|
"info": "You may have forgotten to add the {{action}} component to {{resource}} resource.",
|
||||||
"resource404": "Are you sure you have created the {{resource}} resource.",
|
"resource404": "Are you sure you have created the {{resource}} resource.",
|
||||||
"backHome": "Back Home"
|
"backHome": "Back Home"
|
||||||
}
|
}
|
||||||
@@ -163,5 +163,90 @@
|
|||||||
"error": "auto save failure",
|
"error": "auto save failure",
|
||||||
"loading": "saving...",
|
"loading": "saving...",
|
||||||
"idle": "waiting for changes"
|
"idle": "waiting for changes"
|
||||||
|
},
|
||||||
|
"undefined": {
|
||||||
|
"undefined": "No translation",
|
||||||
|
"titles": {
|
||||||
|
"list": "No translation"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"schemas": {
|
||||||
|
"individual": {
|
||||||
|
"type": "Individual",
|
||||||
|
"lastname": "Lastname",
|
||||||
|
"surnames": "Surname",
|
||||||
|
"day_of_birth": "Date of birth",
|
||||||
|
"firstname": "Firstname",
|
||||||
|
"place_of_birth": "Place of birth",
|
||||||
|
"middlename": "Middlename"
|
||||||
|
},
|
||||||
|
"corporation": {
|
||||||
|
"type": "Corporation",
|
||||||
|
"activity": "Activity",
|
||||||
|
"title": "Title",
|
||||||
|
"employees": "Employees"
|
||||||
|
},
|
||||||
|
"employee": {
|
||||||
|
"position": "Position",
|
||||||
|
"entity_id": "Identity"
|
||||||
|
},
|
||||||
|
"institution": {
|
||||||
|
"type": "Institution",
|
||||||
|
"title": "Title",
|
||||||
|
"activity": "Activity",
|
||||||
|
"employees": "Employees"
|
||||||
|
},
|
||||||
|
"entity": {
|
||||||
|
"entity_data": "Informations",
|
||||||
|
"address": "Address"
|
||||||
|
},
|
||||||
|
"provision_template": {
|
||||||
|
"name": "Name",
|
||||||
|
"title": "Title",
|
||||||
|
"body": "Body"
|
||||||
|
},
|
||||||
|
"contract_template": {
|
||||||
|
"name": "Name",
|
||||||
|
"title": "Title",
|
||||||
|
"provisions": "Provisions",
|
||||||
|
"parties": "Parties",
|
||||||
|
"variables": "Variables"
|
||||||
|
},
|
||||||
|
"party_template": {
|
||||||
|
"entity_id": "Party Template",
|
||||||
|
"representative_id": "Representative",
|
||||||
|
"part": "Part"
|
||||||
|
},
|
||||||
|
"provision_template_reference": {
|
||||||
|
"provision_template_id": "Provision Template"
|
||||||
|
},
|
||||||
|
"dictionary_entry": {
|
||||||
|
"key": "Variable",
|
||||||
|
"value": "Value"
|
||||||
|
},
|
||||||
|
"contract_draft": {
|
||||||
|
"name": "Name",
|
||||||
|
"title": "Title",
|
||||||
|
"parties": "Parties",
|
||||||
|
"provisions": "Provisions",
|
||||||
|
"variables": "Variables"
|
||||||
|
},
|
||||||
|
"draft_party": {
|
||||||
|
"entity_id": "Client",
|
||||||
|
"part": "Part",
|
||||||
|
"representative_id": "Representative"
|
||||||
|
},
|
||||||
|
"contract_provision_template_reference": {
|
||||||
|
"provision_template_id": "Provision Template",
|
||||||
|
"type": "Type"
|
||||||
|
},
|
||||||
|
"provision_genuine": {
|
||||||
|
"title": "Title",
|
||||||
|
"body": "Body",
|
||||||
|
"type": "Type"
|
||||||
|
},
|
||||||
|
"draft_provision": {
|
||||||
|
"provision": "Provision"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -73,8 +73,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"error": {
|
"error": {
|
||||||
"info": "Il manque l'action {{action}} component à la ressource {{resource}} .",
|
|
||||||
"404": "Cette page n'existe pas.",
|
"404": "Cette page n'existe pas.",
|
||||||
|
"info": "Il manque l'action {{action}} component à la ressource {{resource}} .",
|
||||||
"resource404": "Cette page n'existe pas.",
|
"resource404": "Cette page n'existe pas.",
|
||||||
"backHome": "Retour à l'accueil"
|
"backHome": "Retour à l'accueil"
|
||||||
}
|
}
|
||||||
@@ -163,5 +163,90 @@
|
|||||||
"error": "Sauvegarde automatique ratée",
|
"error": "Sauvegarde automatique ratée",
|
||||||
"loading": "Sauvegarde...",
|
"loading": "Sauvegarde...",
|
||||||
"idle": "En attente de modification"
|
"idle": "En attente de modification"
|
||||||
|
},
|
||||||
|
"undefined": {
|
||||||
|
"undefined": "No translation",
|
||||||
|
"titles": {
|
||||||
|
"list": "No translation"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"schemas": {
|
||||||
|
"individual": {
|
||||||
|
"type": "Particulier",
|
||||||
|
"middlename": "Autres prénoms",
|
||||||
|
"lastname": "Nom",
|
||||||
|
"firstname": "Prénom",
|
||||||
|
"day_of_birth": "Date de naissance",
|
||||||
|
"surnames": "Surnoms",
|
||||||
|
"place_of_birth": "Lieu de naissance"
|
||||||
|
},
|
||||||
|
"corporation": {
|
||||||
|
"type": "Entreprise",
|
||||||
|
"title": "Titre",
|
||||||
|
"activity": "Activité",
|
||||||
|
"employees": "Employés"
|
||||||
|
},
|
||||||
|
"employee": {
|
||||||
|
"entity_id": "Identité",
|
||||||
|
"position": "Poste"
|
||||||
|
},
|
||||||
|
"institution": {
|
||||||
|
"type": "Institution",
|
||||||
|
"title": "Titre",
|
||||||
|
"employees": "Employés",
|
||||||
|
"activity": "Activité"
|
||||||
|
},
|
||||||
|
"entity": {
|
||||||
|
"entity_data": "Informations",
|
||||||
|
"address": "Adresse"
|
||||||
|
},
|
||||||
|
"provision_template": {
|
||||||
|
"name": "Nom",
|
||||||
|
"body": "Corps",
|
||||||
|
"title": "Titre"
|
||||||
|
},
|
||||||
|
"contract_template": {
|
||||||
|
"name": "Nom",
|
||||||
|
"title": "Titre",
|
||||||
|
"parties": "Parties",
|
||||||
|
"provisions": "Clauses",
|
||||||
|
"variables": "Variables"
|
||||||
|
},
|
||||||
|
"party_template": {
|
||||||
|
"entity_id": "Entité",
|
||||||
|
"part": "Rôle",
|
||||||
|
"representative_id": "Représentant"
|
||||||
|
},
|
||||||
|
"provision_template_reference": {
|
||||||
|
"provision_template_id": "Template de clause"
|
||||||
|
},
|
||||||
|
"dictionary_entry": {
|
||||||
|
"key": "Variable",
|
||||||
|
"value": "Valeur"
|
||||||
|
},
|
||||||
|
"contract_draft": {
|
||||||
|
"name": "Nom",
|
||||||
|
"parties": "Parties",
|
||||||
|
"title": "Titre",
|
||||||
|
"provisions": "Clauses",
|
||||||
|
"variables": "Variables"
|
||||||
|
},
|
||||||
|
"draft_party": {
|
||||||
|
"part": "Rôle",
|
||||||
|
"representative_id": "Représentant",
|
||||||
|
"entity_id": "Entité"
|
||||||
|
},
|
||||||
|
"contract_provision_template_reference": {
|
||||||
|
"type": "Template",
|
||||||
|
"provision_template_id": "Template de clause"
|
||||||
|
},
|
||||||
|
"provision_genuine": {
|
||||||
|
"type": "Personalisée",
|
||||||
|
"title": "Titre",
|
||||||
|
"body": "Corps"
|
||||||
|
},
|
||||||
|
"draft_provision": {
|
||||||
|
"provision": "Clause"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -10,8 +10,9 @@ i18n
|
|||||||
.init({
|
.init({
|
||||||
supportedLngs: ["EN", "FR"],
|
supportedLngs: ["EN", "FR"],
|
||||||
backend: {
|
backend: {
|
||||||
loadPath: "/locales/{{lng}}/{{ns}}.json", // locale files path
|
loadPath: "/locales/{{lng}}/{{ns}}.json", // "http/locales/{{lng}}/{{ns}}.json"
|
||||||
},
|
},
|
||||||
|
//saveMissing: true,
|
||||||
ns: ["common"],
|
ns: ["common"],
|
||||||
defaultNS: "common",
|
defaultNS: "common",
|
||||||
fallbackLng: ["EN", "FR"],
|
fallbackLng: ["EN", "FR"],
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { JSONSchema7Definition } from "json-schema";
|
|
||||||
import { RJSFSchema } from '@rjsf/utils';
|
import { RJSFSchema } from '@rjsf/utils';
|
||||||
|
import i18n from '../../../i18n'
|
||||||
|
|
||||||
const API_URL = "/api/v1";
|
const API_URL = "/api/v1";
|
||||||
|
|
||||||
@@ -19,6 +19,10 @@ const getJsonschema = async (): Promise<RJSFSchema> => {
|
|||||||
return rawSchema;
|
return rawSchema;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function convertCamelToSnake(str: string): string {
|
||||||
|
return str.replace(/([a-zA-Z])(?=[A-Z])/g,'$1_').toLowerCase()
|
||||||
|
}
|
||||||
|
|
||||||
function buildResource(rawSchemas: RJSFSchema, resourceName: string) {
|
function buildResource(rawSchemas: RJSFSchema, resourceName: string) {
|
||||||
let resource;
|
let resource;
|
||||||
|
|
||||||
@@ -45,6 +49,12 @@ function buildResource(rawSchemas: RJSFSchema, resourceName: string) {
|
|||||||
} else if (is_array(prop) && is_reference(prop.items)) {
|
} else if (is_array(prop) && is_reference(prop.items)) {
|
||||||
resolveReference(rawSchemas, resource, prop.items);
|
resolveReference(rawSchemas, resource, prop.items);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (prop.hasOwnProperty("title")) {
|
||||||
|
const shortResourceName = convertCamelToSnake(resourceName.replace(/(-Input|Create|Update)$/g, ""));
|
||||||
|
prop.title = i18n.t(`schemas.${shortResourceName}.${convertCamelToSnake(prop_name)}`, prop.title);
|
||||||
|
console.log(`schemas.${shortResourceName}.${convertCamelToSnake(prop_name)}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return resource;
|
return resource;
|
||||||
@@ -161,7 +171,6 @@ function path_exists(rawSchemas: RJSFSchema, resource: RJSFSchema, path: string)
|
|||||||
return has_descendant(rawSchemas, resource, path);
|
return has_descendant(rawSchemas, resource, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return has_descendant(rawSchemas, resource, path.substring(0, pointFirstPosition))
|
return has_descendant(rawSchemas, resource, path.substring(0, pointFirstPosition))
|
||||||
&& path_exists(
|
&& path_exists(
|
||||||
rawSchemas,
|
rawSchemas,
|
||||||
|
|||||||
11
i18n/Dockerfile
Normal file
11
i18n/Dockerfile
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
FROM node:lts-alpine
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
COPY app/package*.json ./
|
||||||
|
RUN npm install
|
||||||
|
|
||||||
|
COPY app/tsconfig*.json ./
|
||||||
|
COPY app/src ./src
|
||||||
|
EXPOSE 8100
|
||||||
|
|
||||||
|
CMD [ "npm", "--watch", "start" ]
|
||||||
26
i18n/app/.gitignore
vendored
Normal file
26
i18n/app/.gitignore
vendored
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
# Logs
|
||||||
|
|
||||||
|
logs
|
||||||
|
_.log
|
||||||
|
npm-debug.log_
|
||||||
|
yarn-debug.log*
|
||||||
|
yarn-error.log*
|
||||||
|
pnpm-debug.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
node_modules
|
||||||
|
dist
|
||||||
|
dist-ssr
|
||||||
|
\*.local
|
||||||
|
|
||||||
|
# Editor directories and files
|
||||||
|
|
||||||
|
.vscode/_
|
||||||
|
!.vscode/extensions.json
|
||||||
|
.idea
|
||||||
|
.DS_Store
|
||||||
|
_.suo
|
||||||
|
_.ntvs_
|
||||||
|
_.njsproj
|
||||||
|
_.sln
|
||||||
|
\*.sw?
|
||||||
1164
i18n/app/package-lock.json
generated
Normal file
1164
i18n/app/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
25
i18n/app/package.json
Normal file
25
i18n/app/package.json
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"name": "i18n Helper",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"start": "ts-node src/index.ts",
|
||||||
|
"build": "tsc",
|
||||||
|
"serve": "node dist/index.js"
|
||||||
|
},
|
||||||
|
"keywords": [],
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"type": "commonjs",
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/express": "^5.0.1",
|
||||||
|
"@types/node": "^22.15.3",
|
||||||
|
"express": "^5.1.0",
|
||||||
|
"ts-node": "^10.9.2",
|
||||||
|
"typescript": "^5.8.3"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"body-parser": "^2.2.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
49
i18n/app/src/index.ts
Normal file
49
i18n/app/src/index.ts
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
import express, { Request, Response } from 'express';
|
||||||
|
import bodyParser from "body-parser";
|
||||||
|
|
||||||
|
import { writeFileSync, readFileSync, existsSync, mkdirSync } from 'fs';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const app = express();
|
||||||
|
app.use(bodyParser.json());
|
||||||
|
const port = process.env.PORT || 8100;
|
||||||
|
|
||||||
|
app.post('/locales/add/:lng/:ns', (req: Request, res: Response) => {
|
||||||
|
const keyPath = Object.keys(req.body)[0];
|
||||||
|
|
||||||
|
const basePath = "public/locales";
|
||||||
|
const lgPath = `${basePath}/${req.params.lng}`;
|
||||||
|
if (!existsSync(lgPath)) {
|
||||||
|
mkdirSync(lgPath);
|
||||||
|
}
|
||||||
|
const filePath = `${lgPath}/common.json`;
|
||||||
|
|
||||||
|
let missingTrans;
|
||||||
|
try {
|
||||||
|
missingTrans = JSON.parse(readFileSync(filePath, 'utf8'));
|
||||||
|
} catch(err) {
|
||||||
|
missingTrans = JSON.parse("{}");
|
||||||
|
}
|
||||||
|
|
||||||
|
let current = missingTrans
|
||||||
|
const splitPath = keyPath.split(".");
|
||||||
|
for (let i=0; i < splitPath.length; i++) {
|
||||||
|
const key = splitPath[i];
|
||||||
|
if (! current.hasOwnProperty(key)) {
|
||||||
|
if (i + 1 == splitPath.length) {
|
||||||
|
current[key] = "No translation";
|
||||||
|
} else {
|
||||||
|
current[key] = JSON.parse("{}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
current = current[key];
|
||||||
|
}
|
||||||
|
writeFileSync(filePath, JSON.stringify(missingTrans, null, 2))
|
||||||
|
|
||||||
|
res.send("OK");
|
||||||
|
});
|
||||||
|
|
||||||
|
app.listen(port, () => {
|
||||||
|
console.log(`Server running at http://localhost:${port}`);
|
||||||
|
});
|
||||||
13
i18n/app/tsconfig.json
Normal file
13
i18n/app/tsconfig.json
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es6",
|
||||||
|
"module": "commonjs",
|
||||||
|
"outDir": "./dist",
|
||||||
|
"strict": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"forceConsistentCasingInFileNames": true
|
||||||
|
},
|
||||||
|
"include": ["src/**/*.ts"],
|
||||||
|
"exclude": ["node_modules"]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user