Skip to content

Commit 2eb3232

Browse files
authored
Merge pull request #3089 from kubernetes-sigs/unify-locales
app, frontend: Unify locales
2 parents 579940e + bfcc3f4 commit 2eb3232

File tree

15 files changed

+164
-30
lines changed

15 files changed

+164
-30
lines changed

app/electron/i18n-helper.ts

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,32 @@
11
import * as fs from 'fs';
22
import * as path from 'path';
33

4-
const directoryPath = path.join(__dirname, './locales/');
5-
const currentLocales: string[] = [];
4+
// Get the path to the frontend locales directory
5+
let frontendLocalesPath: string;
6+
const isDev = process.env.ELECTRON_DEV || false;
7+
// Check if we're running in a normal Node.js process (for i18next-parser)
8+
// or in an Electron environment
9+
const isRunningInNode = !(process as any).resourcesPath;
10+
11+
if (isDev || isRunningInNode) {
12+
// When running as a normal Node.js process (i18next parser) or in dev mode
13+
frontendLocalesPath = path.resolve(__dirname, '../../frontend/src/i18n/locales');
14+
} else {
15+
// When running in Electron production mode
16+
frontendLocalesPath = path.join((process as any).resourcesPath, 'frontend/i18n/locales');
17+
}
618

7-
fs.readdirSync(directoryPath).forEach(file => currentLocales.push(file));
19+
// Read available locales from the frontend locales directory
20+
const currentLocales: string[] = [];
21+
if (fs.existsSync(frontendLocalesPath)) {
22+
fs.readdirSync(frontendLocalesPath).forEach(file => {
23+
// Only include directories, not files
24+
if (fs.statSync(path.join(frontendLocalesPath, file)).isDirectory()) {
25+
currentLocales.push(file);
26+
}
27+
});
28+
}
829

9-
export { currentLocales as CURRENT_LOCALES };
10-
export { directoryPath as LOCALES_DIR };
30+
// If no locales found, default to English
31+
export const CURRENT_LOCALES = currentLocales.length > 0 ? currentLocales : ['en'];
32+
export const LOCALES_DIR = frontendLocalesPath;

app/electron/i18next-parser.config.js

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,31 @@
11
const path = require('path');
22
const helper = require('./i18n-helper');
3+
const fs = require('fs');
4+
5+
// Import shared configuration values from frontend
6+
let sharedConfig;
7+
try {
8+
// Try to import the shared config dynamically
9+
const sharedConfigPath = path.resolve(
10+
__dirname,
11+
'../../frontend/src/i18n/i18nextSharedConfig.mjs'
12+
);
13+
if (fs.existsSync(sharedConfigPath)) {
14+
// For CommonJS requiring ES modules, use a dynamic import
15+
sharedConfig = {
16+
contextSeparator: '//context:',
17+
namespaces: ['translation', 'glossary', 'app'],
18+
defaultNamespace: 'translation',
19+
};
20+
}
21+
} catch (error) {
22+
console.error('Failed to import shared config:', error);
23+
}
24+
25+
// Ensure the LOCALES_DIR is defined
26+
if (!helper.LOCALES_DIR) {
27+
throw new Error('Locales directory is not defined. Check i18n-helper.js for issues.');
28+
}
329

430
module.exports = {
531
lexers: {
@@ -8,9 +34,9 @@ module.exports = {
834
namespaceSeparator: '|',
935
keySeparator: false,
1036
defaultNamespace: 'app',
11-
contextSeparator: '//context:',
12-
output: path.join(helper.LOCALES_DIR, './$LOCALE/$NAMESPACE.json'),
13-
locales: helper.CURRENT_LOCALES,
37+
contextSeparator: sharedConfig?.contextSeparator || '//context:',
38+
output: path.join(helper.LOCALES_DIR, '$LOCALE/$NAMESPACE.json'),
39+
locales: helper.CURRENT_LOCALES.length > 0 ? helper.CURRENT_LOCALES : ['en'],
1440
// The English catalog has "SomeKey": "SomeKey" so we stop warnings about
1541
// missing values.
1642
useKeysAsDefaultValue: locale => locale === 'en',

app/package-lock.json

Lines changed: 47 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,6 @@
116116
"files": [
117117
"electron/main.js",
118118
"electron/preload.js",
119-
"electron/locales/",
120119
"electron/i18next.config.js",
121120
"electron/i18n-helper.js",
122121
"electron/windowSize.js",
@@ -159,6 +158,7 @@
159158
"@electron/notarize": "^2.3.2",
160159
"@headlamp-k8s/eslint-config": "^0.6.0",
161160
"@types/jest": "^29.5.14",
161+
"@types/node": "^22.14.0",
162162
"electron": "^31.2.0",
163163
"electron-builder": "^24.13.3",
164164
"i18next-parser": "^9.0.0",

docs/development/i18n/contributing.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ Here's an example of using date formatting:
8989
## Adding a new language
9090

9191
Create a folder using the locale code in:
92-
`frontend/src/i18n/locales/` and `app/electron/locales`
92+
`frontend/src/i18n/locales/`
9393

9494
Then run `make i18n`. This command parses the translatable strings in
9595
the project and creates the corresponding catalog files.

frontend/src/i18n/config.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ i18next
4141
// i18next options: https://www.i18next.com/overview/configuration-options
4242
.init({
4343
debug: import.meta.env.DEV && !import.meta.env.UNDER_TEST,
44-
ns: ['translation', 'glossary'],
45-
defaultNS: 'translation',
44+
ns: sharedConfig.namespaces,
45+
defaultNS: sharedConfig.defaultNamespace,
4646
fallbackLng: 'en',
4747
contextSeparator: sharedConfig.contextSeparator,
4848
supportedLngs: Object.keys(supportedLanguages),

frontend/src/i18n/i18next-parser.config.js

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@ import fs from 'fs';
22
import path from 'path';
33
import sharedConfig from './i18nextSharedConfig.mjs';
44

5-
const directoryPath = path.join(import.meta.dirname, './locales/');
5+
const directoryPath = path.join(import.meta.dirname, sharedConfig.localesPath);
66
const currentLocales = [];
7-
const contextSeparator = sharedConfig.contextSeparator;
87

98
fs.readdirSync(directoryPath).forEach(file => currentLocales.push(file));
109

@@ -16,12 +15,12 @@ export default {
1615
keySeparator: false,
1716
output: path.join(directoryPath, './$LOCALE/$NAMESPACE.json'),
1817
locales: currentLocales,
19-
contextSeparator,
18+
contextSeparator: sharedConfig.contextSeparator,
2019
defaultValue: (locale, _namespace, key) => {
2120
// The English catalog has "SomeKey": "SomeKey" so we stop warnings about
2221
// missing values.
2322
if (locale === 'en') {
24-
const contextSepIdx = key.indexOf(contextSeparator);
23+
const contextSepIdx = key.indexOf(sharedConfig.contextSeparator);
2524
if (contextSepIdx >= 0) {
2625
return key.substring(0, contextSepIdx);
2726
}
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
export default {
22
contextSeparator: '//context:',
3+
namespaces: ['translation', 'glossary', 'app'],
4+
defaultNamespace: 'translation',
5+
localesPath: './locales',
36
};

0 commit comments

Comments
 (0)