#598: Add localization support to the panel + scripts

This commit is contained in:
Elio Struyf
2023-07-04 10:53:35 +02:00
parent 71743bf292
commit c247af449a
25 changed files with 207 additions and 40 deletions
+9 -1
View File
@@ -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"
}
+9 -2
View File
@@ -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"
}
+4 -2
View File
@@ -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",
+38
View File
@@ -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();
})();
+33
View File
@@ -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');
}
})();
+3 -1
View File
@@ -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);
+4 -2
View File
@@ -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'
}
};
+1 -4
View File
@@ -10,8 +10,5 @@ export enum DashboardCommand {
searchReady = 'searchReady',
// Taxonomy dashboard
setTaxonomyData = 'setTaxonomyData',
// Localization
setLocalization = 'setLocalization'
setTaxonomyData = 'setTaxonomyData'
}
-1
View File
@@ -56,7 +56,6 @@ export enum DashboardMessage {
moveTaxonomy = 'moveTaxonomy',
// Other
getLocalization = 'getLocalization',
getTheme = 'getTheme',
updateSetting = 'updateSetting',
setState = 'setState',
@@ -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<IHeaderProps> = ({
<SyncButton />
<ChoiceButton
title={l10n.t(`header.createContent`)}
title={l10n.t(LocalizationKey.dashboardHeaderCreateContent)}
choices={choiceOptions}
onClick={createContent}
disabled={!settings?.initialized}
@@ -5,6 +5,7 @@ import useThemeColors from '../../hooks/useThemeColors';
import { DashboardMessage } from '../../DashboardMessage';
import { SETTING_DASHBOARD_OPENONSTART } from '../../../constants';
import * as l10n from "@vscode/l10n"
import { LocalizationKey } from '../../../localization';
export interface IStartupProps {
settings: Settings | null;
@@ -55,7 +56,7 @@ export const Startup: React.FunctionComponent<IStartupProps> = ({
)
}`}
>
{l10n.t(`header.startup.label`)}
{l10n.t(LocalizationKey.dashboardHeaderStartupLabel)}
</label>
</div>
</div>
+2 -2
View File
@@ -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);
+3 -1
View File
@@ -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);
@@ -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);
}
}
+1 -15
View File
@@ -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);
+1
View File
@@ -9,3 +9,4 @@ export * from './SnippetListener';
export * from './TelemetryListener';
export * from './TaxonomyListener';
export * from './LogListener';
export * from './LocalizationListener';
+1 -1
View File
@@ -1,2 +1,2 @@
export * from './ModeListener';
export * from './GitListener';
export * from './ModeListener';
@@ -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);
}
}
+1
View File
@@ -7,3 +7,4 @@ export * from './MediaListener';
export * from './ScriptListener';
export * from './SettingsListener';
export * from './TaxonomyListener';
export * from './LocalizationListener';
+1
View File
@@ -0,0 +1 @@
export * from './localization.enum';
+10
View File
@@ -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'
}
+6 -4
View File
@@ -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<IBaseViewProps> = ({
</FeatureFlag>
<FeatureFlag features={mode?.features || []} flag={FEATURE_FLAG.panel.actions}>
<Collapsible id={`base_actions`} title="Actions">
<Collapsible id={`base_actions`} title={l10n.t(LocalizationKey.panelActionsTitle)}>
<div className={`base__actions`}>
<button onClick={openDashboard}>Open dashboard</button>
<button onClick={openDashboard}>{l10n.t(LocalizationKey.panelActionsOpenDashboard)}</button>
<button onClick={openPreview} disabled={!settings?.preview?.host}>
Open preview
{l10n.t(LocalizationKey.panelActionsOpenPreview)}
</button>
<StartServerButton settings={settings} />
<button onClick={createContent}>Create new content</button>
<button onClick={createContent}>{l10n.t(LocalizationKey.panelActionsCreateContent)}</button>
{customActions.map((script) => (
<button key={script.title} onClick={() => runBulkScript(script)}>
@@ -3,6 +3,8 @@ import * as React from 'react';
import { PanelSettings } from '../../models';
import { CommandToCode } from '../CommandToCode';
import useStartCommand from '../hooks/useStartCommand';
import { LocalizationKey } from '../../localization';
import * as l10n from "@vscode/l10n"
export interface IStartServerButtonProps {
settings: PanelSettings | undefined;
@@ -23,8 +25,8 @@ export const StartServerButton: React.FunctionComponent<IStartServerButtonProps>
return startCommand ? (
<>
<button onClick={() => startLocalServer(startCommand)}>Start server</button>
<button onClick={() => stopLocalServer()}>Stop server</button>
<button onClick={() => startLocalServer(startCommand)}>{l10n.t(LocalizationKey.panelActionsStartServer)}</button>
<button onClick={() => stopLocalServer()}>{l10n.t(LocalizationKey.panelActionsStopServer)}</button>
</>
) : null;
};
+7
View File
@@ -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<any>({});
@@ -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);
+17
View File
@@ -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 '';
}
};