Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions openaev-front/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -127,12 +127,14 @@
"node": ">= 22.11.0"
},
"scripts": {
"auto-translation:all": "yarn run auto-translation:fr && yarn run auto-translation:cn",
"auto-translation:all": "yarn run auto-translation:es && yarn run auto-translation:fr && yarn run auto-translation:cn",
"auto-translation:es": "i18n-auto-translation -a deepl-free -p ./src/utils/lang/en.json -t es -k $SUBSCRIPTION_KEY",
"auto-translation:fr": "i18n-auto-translation -a deepl-free -p ./src/utils/lang/en.json -t fr -k $SUBSCRIPTION_KEY",
"auto-translation:cn": "i18n-auto-translation -a deepl-free -p ./src/utils/lang/en.json -t zh -k $SUBSCRIPTION_KEY",
"extract-translation": "node scripts/extract-i18n-keyword.js",
"sort-translation": "node scripts/sort-translation-files.js",
"i18n-checker": "node scripts/i18n-checker.js",
"i18n-checker": "npm run generate-i18n-checker-constant && node scripts/i18n-checker.js",
"generate-i18n-checker-constant": "tsc src/constants/Lang.ts --outDir scripts/constants --skipLibCheck --module ES6 --target ES6",
"start": "vite",
"deprecated-start": "node builder/dev/dev.js",
"build": "node builder/prod/prod.js",
Expand Down
2 changes: 2 additions & 0 deletions openaev-front/scripts/constants/Lang.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const supportedLanguages = ['en', 'es', 'fr', 'zh'];
export const DEFAULT_LANG = 'en';
25 changes: 15 additions & 10 deletions openaev-front/scripts/i18n-checker.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import fs from 'node:fs';
import path from 'path';
import { fileURLToPath } from 'url';

import { DEFAULT_LANG, supportedLanguages } from './constants/Lang.js';

const __filename = fileURLToPath(import.meta.url);

const __dirname = `${path.dirname(__filename)}/../src`;
Expand All @@ -15,15 +17,19 @@ const escapeString = (inputString) => {
// -- Retrieve i18n lang keys --

const computeLangKeys = (lang) => {
let data;
if (lang === 'en') {
data = fs.readFileSync(`${__dirname}/utils/lang/en.json`, { encoding: 'utf8' });
} else if (lang === 'fr') {
data = fs.readFileSync(`${__dirname}/utils/lang/fr.json`, { encoding: 'utf8' });
} else if (lang === 'zh') {
data = fs.readFileSync(`${__dirname}/utils/lang/zh.json`, { encoding: 'utf8' });
const basePath = path.join(__dirname, 'utils', 'lang');

// fallback to English if unsupported
const targetLang = supportedLanguages.includes(lang) ? lang : DEFAULT_LANG;
const filePath = path.join(basePath, `${targetLang}.json`);

try {
return fs.readFileSync(filePath, 'utf8');
} catch (err) {
// eslint-disable-next-line no-console
console.error(`Failed to read language file for "${targetLang}":`, err);
return null;
}
return data;
};

// -- Match missing keys --
Expand Down Expand Up @@ -67,10 +73,9 @@ const checkLanguageSupport = (lang) => {
};

const run = () => {
const languages = ['en', 'fr', 'zh'];
const missingKeys = {};

languages.forEach((lang) => {
supportedLanguages.forEach((lang) => {
const keys = checkLanguageSupport(lang);
if (keys.length > 0) {
missingKeys[lang] = keys;
Expand Down
4 changes: 4 additions & 0 deletions openaev-front/src/admin/components/utils/OptionItems.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ export const langItems = (t: (text: string) => string) => [
value: 'en',
label: t('English'),
},
{
value: 'es',
label: t('Spanish'),
},
{
value: 'fr',
label: t('French'),
Expand Down
11 changes: 8 additions & 3 deletions openaev-front/src/components/AppIntlProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,37 +1,42 @@
import 'cronstrue/locales/fr';
import 'cronstrue/locales/en';
import 'cronstrue/locales/es';
import 'cronstrue/locales/zh_CN';

import { LocalizationProvider } from '@mui/x-date-pickers';
import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns';
import { enUS as dateFnsEnUSLocale, fr as dateFnsFrLocale, zhCN as dateFnsZhCNLocale } from 'date-fns/locale';
import { enUS as dateFnsEnUSLocale, es as dateFnsEsLocale, fr as dateFnsFrLocale, zhCN as dateFnsZhCNLocale } from 'date-fns/locale';
import moment from 'moment';
import { type FunctionComponent, type ReactElement, useEffect } from 'react';
import { IntlProvider } from 'react-intl';

import { type LoggedHelper } from '../actions/helper';
import { DEFAULT_LANG } from '../constants/Lang';
import { useHelper } from '../store';
import { DEFAULT_LANG } from '../utils/BrowserLanguage';
import enOpenAEV from '../utils/lang/en.json';
import esOpenAEV from '../utils/lang/es.json';
import frOpenAEV from '../utils/lang/fr.json';
import zhOpenAEV from '../utils/lang/zh.json';

type Lang = 'en' | 'fr' | 'zh';
type Lang = 'en' | 'es' | 'fr' | 'zh';

const dateFnsLocaleMap = {
en: dateFnsEnUSLocale,
es: dateFnsEsLocale,
fr: dateFnsFrLocale,
zh: dateFnsZhCNLocale,
};

const oaevLocaleMap = {
en: enOpenAEV,
es: esOpenAEV,
fr: frOpenAEV,
zh: zhOpenAEV,
};

const momentMap = {
en: 'en-us',
es: 'es-es',
fr: 'fr-fr',
zh: 'zh-cn',
};
Expand Down
3 changes: 3 additions & 0 deletions openaev-front/src/constants/Lang.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const supportedLanguages = ['en', 'es', 'fr', 'zh'];

export const DEFAULT_LANG = 'en';
2 changes: 2 additions & 0 deletions openaev-front/src/utils/Action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { store } from '../store';
import { MESSAGING$ } from './Environment';
import { notifyErrorHandler } from './error/errorHandlerUtil';
import enOpenAEV from './lang/en.json';
import esOpenAEV from './lang/es.json';
import frOpenAEV from './lang/fr.json';
import zhOpenAEV from './lang/zh.json';

Expand All @@ -25,6 +26,7 @@ const cache = createIntlCache();

const langOpenAEV = {
en: enOpenAEV,
es: esOpenAEV,
fr: frOpenAEV,
zh: zhOpenAEV,
};
Expand Down
7 changes: 3 additions & 4 deletions openaev-front/src/utils/BrowserLanguage.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as R from 'ramda';

export const DEFAULT_LANG = 'en';
import { DEFAULT_LANG, supportedLanguages } from '../constants/Lang';

// These window.navigator contain language information
// 1. languages -> [] of preferred languages (eg ["en-US", "zh-CN", "ja-JP"]) Firefox^32, Chrome^32
// 2. language -> Preferred language as String (eg "en-US") Firefox^5, IE^11, Safari,
Expand All @@ -16,15 +17,13 @@ const browserLanguagePropertyKeys = [
'systemLanguage',
];

const availableLanguages = ['en', 'fr', 'zh'];

const detectedLocale = R.pipe(
R.pick(browserLanguagePropertyKeys), // Get only language properties
R.values(), // Get values of the properties
R.flatten(), // flatten all arrays
R.reject(R.isNil), // Remove undefined values
R.map((x: string) => x.substr(0, 2)),
R.find((x: string) => R.includes(x, availableLanguages)), // Returns first language matched in languages
R.find((x: string) => R.includes(x, supportedLanguages)), // Returns first language matched in languages
);

export default detectedLocale(window.navigator) || DEFAULT_LANG; // If no locale is detected, fallback to 'en'
11 changes: 6 additions & 5 deletions openaev-front/src/utils/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,9 @@
"Agents": "Agents",
"Agents Privileges": "Agents Privileges",
"Aggressive": "Aggressive",
"AI in progress": "AI rule generation in progress. This may take some time. Please do not leave this page.",
"AI Powered": "AI Powered",
"AI remediation may be outdated: payload updated after remediation": "AI remediation may be outdated:\n payload updated after remediation",
"AI in progress": "AI rule generation in progress. This may take some time. Please do not leave this page.",
"Alerts": "Alerts",
"All assets (per group) must validate the expectation": "All assets (per group) must validate the expectation",
"All categories": "All categories",
Expand Down Expand Up @@ -184,8 +184,8 @@
"Background color": "Background color",
"backlabel": "backlabel",
"backuri": "backuri",
"Bad request": "Bad request",
"Bad Gateway": "Bad Gateway",
"Bad request": "Bad request",
"base_agent_side": "Agents",
"base_agents_side": "Agents",
"base_asset_group_side": "Asset group",
Expand Down Expand Up @@ -386,8 +386,6 @@
"custom_dashboard_step_type": "Visualization",
"Customization": "Customization",
"Customize columns": "Customize columns",
"VULNERABILITY ID": "VULNERABILITY ID",
"vulnerability_external_id": "VULNERABILITY ID",
"CVSS must be at least 0.0": "CVSS must be at least 0.0",
"CVSS must be at most 10.0": "CVSS must be at most 10.0",
"CVSS score is required": "CVSS score is required",
Expand Down Expand Up @@ -1216,6 +1214,7 @@
"Only SMS and emails related injects will be tested": "Only SMS and emails related injects will be tested",
"Only weekday": "Only weekday",
"OpenAEV": "OpenAEV",
"OpenAEV EE license terms": "OpenAEV EE license terms",
"OpenAEV EE license terms and conditions of usage": "OpenAEV EE license terms and conditions of usage",
"OpenAEV Enterprise Edition (EE) license agreement": "OpenAEV Enterprise Edition (EE) license agreement",
"OpenAEV Enterprise Edition (EE) provides highly demanding organizations with a version that includes additional and powerful features, which require specific investments in research and development.": "OpenAEV Enterprise Edition (EE) provides highly demanding organizations with a version that includes additional and powerful features, which require specific investments in research and development.",
Expand All @@ -1234,7 +1233,6 @@
"openaev_ovh_sms": "SMS (OVH)",
"openaev_twitter": "Twitter",
"openaev_welcome": "Welcome",
"OpenAEVEE license terms": "OpenAEVEE license terms",
"OpenCTI": "OpenCTI",
"OpenERM": "OpenERM",
"OpenMTD": "OpenMTD",
Expand Down Expand Up @@ -1579,6 +1577,7 @@
"Source asset groups": "Source asset groups",
"Source assets": "Source assets",
"Space": "Space",
"Spanish": "Spanish",
"Stacked": "Stacked",
"Standard": "Standard",
"Standard Installation": "Standard Installation",
Expand Down Expand Up @@ -1881,9 +1880,11 @@
"Vulnerabilities": "Vulnerabilities",
"VULNERABILITY": "Vulnerability",
"Vulnerability": "Vulnerability",
"VULNERABILITY ID": "VULNERABILITY ID",
"Vulnerability Name": "Vulnerability Name",
"Vulnerability Remediation": "Vulnerability Remediation",
"Vulnerability status": "Vulnerability status",
"vulnerability_external_id": "VULNERABILITY ID",
"vulnerability-exploitation": "Vulnerability Exploitation",
"Vulnerable": "Vulnerable",
"vulnerable_endpoint_action": "Recommended action",
Expand Down
Loading