diff --git a/l10n/bundle.l10n.de.json b/l10n/bundle.l10n.de.json index 8a56e539..02a94dd6 100644 --- a/l10n/bundle.l10n.de.json +++ b/l10n/bundle.l10n.de.json @@ -1,4 +1,12 @@ { "header.createContent": "Inhalte erstellen", - "header.startup.label": "Beim Start öffnen?" + "header.startup.label": "Beim Start öffnen?", + "dashboard.header.createContent": "🚧: Create content", + "dashboard.header.startup.label": "🚧: Open on startup?", + "panel.actions.title": "🚧: Actions", + "panel.actions.openDashboard": "🚧: Open dashboard", + "panel.actions.openPreview": "🚧: Open preview", + "panel.actions.startServer": "🚧: Start server", + "panel.actions.stopServer": "🚧: Stop server", + "panel.actions.createContent": "🚧: Create content" } \ No newline at end of file diff --git a/l10n/bundle.l10n.json b/l10n/bundle.l10n.json index 5075f245..05c765eb 100644 --- a/l10n/bundle.l10n.json +++ b/l10n/bundle.l10n.json @@ -1,4 +1,11 @@ { - "header.createContent": "Create content", - "header.startup.label": "Open on startup?" + "dashboard.header.createContent": "Create content", + "dashboard.header.startup.label": "Open on startup?", + + "panel.actions.title": "Actions", + "panel.actions.openDashboard": "Open dashboard", + "panel.actions.openPreview": "Open preview", + "panel.actions.startServer": "Start server", + "panel.actions.stopServer": "Stop server", + "panel.actions.createContent": "Create content" } \ No newline at end of file diff --git a/package.json b/package.json index 13a20065..c9e1a8ac 100644 --- a/package.json +++ b/package.json @@ -2374,7 +2374,7 @@ }] }, "scripts": { - "dev:ext": "npm run clean && npm-run-all --parallel watch:*", + "dev:ext": "npm run clean && npm run localization:generate && npm-run-all --parallel watch:*", "vscode:prepublish": "npm run clean && npm-run-all --parallel prod:*", "build:ext": "npm run clean && npm-run-all --parallel dev:build:*", "watch:ext": "webpack --mode development --watch --config ./webpack/extension.config.js", @@ -2392,7 +2392,9 @@ "clean:test": "rm ./e2e/sample/frontmatter.json || exit 0 && rm -rf ./e2e/sample/.frontmatter || exit 0", "test": "pnpm lint; tsc -p tsconfig.e2e.json && npm run clean:test && pnpm i -g @vscode/vsce && node ./e2e/out/runTests.js", "lint": "eslint --max-warnings=0 ./src/{commands,components}", - "prettier": "prettier --write ./src" + "prettier": "prettier --write ./src", + "localization:generate": "node scripts/generate-localization-enum.js", + "localization:sync": "node scripts/sync-localization.js" }, "devDependencies": { "@actions/core": "^1.8.2", diff --git a/scripts/generate-localization-enum.js b/scripts/generate-localization-enum.js new file mode 100644 index 00000000..f05a7d7b --- /dev/null +++ b/scripts/generate-localization-enum.js @@ -0,0 +1,38 @@ +const fs = require('fs'); +const path = require('path'); + +const camlCase = (str) => { + const words = str.split('.'); + const firstWord = words.shift(); + const rest = words.map((word) => { + return word.charAt(0).toUpperCase() + word.slice(1); + }); + return firstWord + rest.join(''); +}; + +(async () => { + // Get the EN file + const enFile = fs.readFileSync(path.join(__dirname, '../l10n/bundle.l10n.json'), 'utf8'); + + // Parse the EN file + const en = JSON.parse(enFile); + + const keys = Object.keys(en); + + // Create an enum file + const enumFile = fs.createWriteStream(path.join(__dirname, '../src/localization/localization.enum.ts')); + + // Write the enum file header + enumFile.write(`export enum LocalizationKey {\n`); + + // Write the enum values + keys.forEach((key, index) => { + enumFile.write(` ${camlCase(key)} = '${key}'${index === keys.length - 1 ? '' : ','}\n`); + }); + + // Write the enum file footer + enumFile.write(`}\n`); + + // Close the enum file + enumFile.close(); +})(); \ No newline at end of file diff --git a/scripts/sync-localization.js b/scripts/sync-localization.js new file mode 100644 index 00000000..033f5682 --- /dev/null +++ b/scripts/sync-localization.js @@ -0,0 +1,33 @@ +const fs = require('fs'); +const path = require('path'); + +(async () => { + // Get all the files from the l10n directory + const files = fs.readdirSync(path.join(__dirname, '../l10n')); + + // Get the EN file + const enFile = fs.readFileSync(path.join(__dirname, '../l10n/bundle.l10n.json'), 'utf8'); + const enContent = JSON.parse(enFile); + const enKeys = Object.keys(enContent); + + for (const file of files) { + if (file.endsWith(`bundle.l10n.json`)) { + continue; + } + + // Get the file content + const fileContent = fs.readFileSync(path.join(__dirname, `../l10n/${file}`), 'utf8'); + const content = JSON.parse(fileContent); + + // Loop through the EN keys + for (const key of enKeys) { + // If the key does not exist in the file, add it + if (!content[key]) { + content[key] = `🚧: ${enContent[key]}`; + } + } + + // Write the file + fs.writeFileSync(path.join(__dirname, `../l10n/${file}`), JSON.stringify(content, null, 2), 'utf8'); + } +})(); \ No newline at end of file diff --git a/src/commands/Dashboard.ts b/src/commands/Dashboard.ts index 04212bfc..b74c796d 100644 --- a/src/commands/Dashboard.ts +++ b/src/commands/Dashboard.ts @@ -22,7 +22,8 @@ import { ExtensionListener, SnippetListener, TaxonomyListener, - LogListener + LogListener, + LocalizationListener } from '../listeners/dashboard'; import { MediaListener as PanelMediaListener } from '../listeners/panel'; import { GitListener, ModeListener } from '../listeners/general'; @@ -166,6 +167,7 @@ export class Dashboard { Dashboard.webview.webview.onDidReceiveMessage(async (msg) => { Logger.info(`Receiving message from webview: ${msg.command}`); + LocalizationListener.process(msg); DashboardListener.process(msg); ExtensionListener.process(msg); MediaListener.process(msg); diff --git a/src/constants/GeneralCommands.ts b/src/constants/GeneralCommands.ts index 77c738da..af8e0256 100644 --- a/src/constants/GeneralCommands.ts +++ b/src/constants/GeneralCommands.ts @@ -2,10 +2,12 @@ export const GeneralCommands = { toWebview: { setMode: 'setMode', gitSyncingStart: 'gitSyncingStart', - gitSyncingEnd: 'gitSyncingEnd' + gitSyncingEnd: 'gitSyncingEnd', + setLocalization: 'setLocalization' }, toVSCode: { openLink: 'openLink', - gitSync: 'gitSync' + gitSync: 'gitSync', + getLocalization: 'getLocalization' } }; diff --git a/src/dashboardWebView/DashboardCommand.ts b/src/dashboardWebView/DashboardCommand.ts index b4d80f93..465d2ebd 100644 --- a/src/dashboardWebView/DashboardCommand.ts +++ b/src/dashboardWebView/DashboardCommand.ts @@ -10,8 +10,5 @@ export enum DashboardCommand { searchReady = 'searchReady', // Taxonomy dashboard - setTaxonomyData = 'setTaxonomyData', - - // Localization - setLocalization = 'setLocalization' + setTaxonomyData = 'setTaxonomyData' } diff --git a/src/dashboardWebView/DashboardMessage.ts b/src/dashboardWebView/DashboardMessage.ts index 2bbba352..a1427074 100644 --- a/src/dashboardWebView/DashboardMessage.ts +++ b/src/dashboardWebView/DashboardMessage.ts @@ -56,7 +56,6 @@ export enum DashboardMessage { moveTaxonomy = 'moveTaxonomy', // Other - getLocalization = 'getLocalization', getTheme = 'getTheme', updateSetting = 'updateSetting', setState = 'setState', diff --git a/src/dashboardWebView/components/Header/Header.tsx b/src/dashboardWebView/components/Header/Header.tsx index d97d2c58..e2a49d4d 100644 --- a/src/dashboardWebView/components/Header/Header.tsx +++ b/src/dashboardWebView/components/Header/Header.tsx @@ -30,6 +30,7 @@ import { Startup } from './Startup'; import { Navigation } from './Navigation'; import { ProjectSwitcher } from './ProjectSwitcher'; import * as l10n from '@vscode/l10n'; +import { LocalizationKey } from '../../../localization'; export interface IHeaderProps { header?: React.ReactNode; @@ -169,7 +170,7 @@ export const Header: React.FunctionComponent = ({ = ({ ) }`} > - {l10n.t(`header.startup.label`)} + {l10n.t(LocalizationKey.dashboardHeaderStartupLabel)} diff --git a/src/dashboardWebView/hooks/useMessages.tsx b/src/dashboardWebView/hooks/useMessages.tsx index f51d754d..f5df9eb4 100644 --- a/src/dashboardWebView/hooks/useMessages.tsx +++ b/src/dashboardWebView/hooks/useMessages.tsx @@ -60,7 +60,7 @@ export default function useMessages() { case GeneralCommands.toWebview.setMode: setMode(message.payload); break; - case DashboardCommand.setLocalization: + case GeneralCommands.toWebview.setLocalization: l10n.config({ contents: message.payload }) @@ -76,7 +76,7 @@ export default function useMessages() { Messenger.send(DashboardMessage.getTheme); Messenger.send(DashboardMessage.getData); Messenger.send(DashboardMessage.getMode); - Messenger.send(DashboardMessage.getLocalization); + Messenger.send(GeneralCommands.toVSCode.getLocalization); return () => { Messenger.unlisten(messageListener); diff --git a/src/explorerView/ExplorerView.ts b/src/explorerView/ExplorerView.ts index 0d28140f..110d4365 100644 --- a/src/explorerView/ExplorerView.ts +++ b/src/explorerView/ExplorerView.ts @@ -6,7 +6,8 @@ import { TaxonomyListener, DataListener, SettingsListener, - FieldsListener + FieldsListener, + LocalizationListener } from './../listeners/panel'; import { SETTING_EXPERIMENTAL, SETTING_EXTENSIBILITY_SCRIPTS, TelemetryEvent } from '../constants'; import { @@ -98,6 +99,7 @@ export class ExplorerView implements WebviewViewProvider, Disposable { webviewView.webview.onDidReceiveMessage(async (msg) => { Logger.info(`Receiving message from webview to panel: ${msg.command}`); + LocalizationListener.process(msg); FieldsListener.process(msg); ArticleListener.process(msg); DataListener.process(msg); diff --git a/src/listeners/dashboard/LocalizationListener.ts b/src/listeners/dashboard/LocalizationListener.ts new file mode 100644 index 00000000..34cde614 --- /dev/null +++ b/src/listeners/dashboard/LocalizationListener.ts @@ -0,0 +1,24 @@ +import { GeneralCommands } from '../../constants'; +import { PostMessageData } from '../../models'; +import { BaseListener } from './BaseListener'; +import { getLocalizationFile } from '../../utils/getLocalizationFile'; + +export class LocalizationListener extends BaseListener { + /** + * Process the messages + * @param msg + */ + public static process(msg: PostMessageData) { + switch (msg.command) { + case GeneralCommands.toVSCode.getLocalization: + this.getLocalization(); + break; + } + } + + public static async getLocalization() { + const fileContents = await getLocalizationFile(); + + this.sendMsg(GeneralCommands.toWebview.setLocalization as any, fileContents); + } +} diff --git a/src/listeners/dashboard/SettingsListener.ts b/src/listeners/dashboard/SettingsListener.ts index 9341ecc2..93d5a9a4 100644 --- a/src/listeners/dashboard/SettingsListener.ts +++ b/src/listeners/dashboard/SettingsListener.ts @@ -1,5 +1,5 @@ import { join } from 'path'; -import { commands, Uri, l10n } from 'vscode'; +import { commands, Uri } from 'vscode'; import { Folders } from '../../commands/Folders'; import { COMMAND_NAME, @@ -21,7 +21,6 @@ import { DataListener } from '../panel'; import { MarkdownFoldingProvider } from '../../providers/MarkdownFoldingProvider'; import { ModeSwitch } from '../../services/ModeSwitch'; import { PagesListener } from './PagesListener'; -import { readFileAsync } from '../../utils'; export class SettingsListener extends BaseListener { /** @@ -35,9 +34,6 @@ export class SettingsListener extends BaseListener { case DashboardMessage.getData: this.getSettings(); break; - case DashboardMessage.getLocalization: - this.getLocalization(); - break; case DashboardMessage.updateSetting: this.update(msg.payload); break; @@ -53,16 +49,6 @@ export class SettingsListener extends BaseListener { } } - public static async getLocalization() { - const localeFilePath = - l10n.uri?.fsPath || - Uri.parse(`${Extension.getInstance().extensionPath}/l10n/bundle.l10n.json`).fsPath; - - const fileContents = await readFileAsync(localeFilePath, 'utf-8'); - - this.sendMsg(DashboardCommand.setLocalization, fileContents); - } - public static async switchProject(project: string) { if (project) { this.sendMsg(DashboardCommand.loading, true); diff --git a/src/listeners/dashboard/index.ts b/src/listeners/dashboard/index.ts index 8ede40ed..2e373d4a 100644 --- a/src/listeners/dashboard/index.ts +++ b/src/listeners/dashboard/index.ts @@ -9,3 +9,4 @@ export * from './SnippetListener'; export * from './TelemetryListener'; export * from './TaxonomyListener'; export * from './LogListener'; +export * from './LocalizationListener'; diff --git a/src/listeners/general/index.ts b/src/listeners/general/index.ts index 6af09d8f..d91b1703 100644 --- a/src/listeners/general/index.ts +++ b/src/listeners/general/index.ts @@ -1,2 +1,2 @@ -export * from './ModeListener'; export * from './GitListener'; +export * from './ModeListener'; diff --git a/src/listeners/panel/LocalizationListener.ts b/src/listeners/panel/LocalizationListener.ts new file mode 100644 index 00000000..34cde614 --- /dev/null +++ b/src/listeners/panel/LocalizationListener.ts @@ -0,0 +1,24 @@ +import { GeneralCommands } from '../../constants'; +import { PostMessageData } from '../../models'; +import { BaseListener } from './BaseListener'; +import { getLocalizationFile } from '../../utils/getLocalizationFile'; + +export class LocalizationListener extends BaseListener { + /** + * Process the messages + * @param msg + */ + public static process(msg: PostMessageData) { + switch (msg.command) { + case GeneralCommands.toVSCode.getLocalization: + this.getLocalization(); + break; + } + } + + public static async getLocalization() { + const fileContents = await getLocalizationFile(); + + this.sendMsg(GeneralCommands.toWebview.setLocalization as any, fileContents); + } +} diff --git a/src/listeners/panel/index.ts b/src/listeners/panel/index.ts index f8e80e22..57191504 100644 --- a/src/listeners/panel/index.ts +++ b/src/listeners/panel/index.ts @@ -7,3 +7,4 @@ export * from './MediaListener'; export * from './ScriptListener'; export * from './SettingsListener'; export * from './TaxonomyListener'; +export * from './LocalizationListener'; diff --git a/src/localization/index.ts b/src/localization/index.ts new file mode 100644 index 00000000..f831950d --- /dev/null +++ b/src/localization/index.ts @@ -0,0 +1 @@ +export * from './localization.enum'; diff --git a/src/localization/localization.enum.ts b/src/localization/localization.enum.ts new file mode 100644 index 00000000..b7624d02 --- /dev/null +++ b/src/localization/localization.enum.ts @@ -0,0 +1,10 @@ +export enum LocalizationKey { + dashboardHeaderCreateContent = 'dashboard.header.createContent', + dashboardHeaderStartupLabel = 'dashboard.header.startup.label', + panelActionsTitle = 'panel.actions.title', + panelActionsOpenDashboard = 'panel.actions.openDashboard', + panelActionsOpenPreview = 'panel.actions.openPreview', + panelActionsStartServer = 'panel.actions.startServer', + panelActionsStopServer = 'panel.actions.stopServer', + panelActionsCreateContent = 'panel.actions.createContent' +} diff --git a/src/panelWebView/components/BaseView.tsx b/src/panelWebView/components/BaseView.tsx index 6670cfb3..f427e12f 100644 --- a/src/panelWebView/components/BaseView.tsx +++ b/src/panelWebView/components/BaseView.tsx @@ -12,6 +12,8 @@ import { FEATURE_FLAG } from '../../constants/Features'; import { Messenger } from '@estruyf/vscode/dist/client'; import { GitAction } from './Git/GitAction'; import { useMemo } from 'react'; +import * as l10n from "@vscode/l10n" +import { LocalizationKey } from '../../localization'; export interface IBaseViewProps { settings: PanelSettings | undefined; @@ -88,15 +90,15 @@ const BaseView: React.FunctionComponent = ({ - +
- + - + {customActions.map((script) => ( - + + ) : null; }; diff --git a/src/panelWebView/hooks/useMessages.tsx b/src/panelWebView/hooks/useMessages.tsx index a9c88ca9..cd92b969 100644 --- a/src/panelWebView/hooks/useMessages.tsx +++ b/src/panelWebView/hooks/useMessages.tsx @@ -10,6 +10,7 @@ import { Messenger } from '@estruyf/vscode/dist/client'; import { EventData } from '@estruyf/vscode/dist/models'; import { useRecoilState } from 'recoil'; import { PanelSettingsAtom } from '../state'; +import * as l10n from '@vscode/l10n'; export default function useMessages() { const [metadata, setMetadata] = useState({}); @@ -50,6 +51,11 @@ export default function useMessages() { case GeneralCommands.toWebview.setMode: setMode(message.payload); break; + case GeneralCommands.toWebview.setLocalization: + l10n.config({ + contents: message.payload + }) + break; } }; @@ -72,6 +78,7 @@ export default function useMessages() { Messenger.send(CommandToCode.getData); Messenger.send(CommandToCode.getMode); + Messenger.send(GeneralCommands.toVSCode.getLocalization); return () => { Messenger.unlisten(messageListener); diff --git a/src/utils/getLocalizationFile.ts b/src/utils/getLocalizationFile.ts new file mode 100644 index 00000000..29c8019f --- /dev/null +++ b/src/utils/getLocalizationFile.ts @@ -0,0 +1,17 @@ +import { Uri, l10n } from 'vscode'; +import { Extension, Logger } from '../helpers'; +import { readFileAsync } from './readFileAsync'; + +export const getLocalizationFile = async () => { + try { + const localeFilePath = + l10n.uri?.fsPath || + Uri.parse(`${Extension.getInstance().extensionPath}/l10n/bundle.l10n.json`).fsPath; + + const fileContents = await readFileAsync(localeFilePath, 'utf-8'); + return fileContents; + } catch (error) { + Logger.error(`Failed to get the localization file: ${(error as Error).message}`); + return ''; + } +};