Skip to content

Commit

Permalink
Merge branch 'issue/850' of github.com:wottpal/vscode-front-matter in…
Browse files Browse the repository at this point in the history
…to wottpal-issue/850
  • Loading branch information
estruyf committed Oct 7, 2024
2 parents 179a71d + aea87a6 commit 38f128e
Show file tree
Hide file tree
Showing 6 changed files with 226 additions and 4 deletions.
7 changes: 6 additions & 1 deletion l10n/bundle.l10n.json
Original file line number Diff line number Diff line change
Expand Up @@ -583,8 +583,13 @@
"commands.i18n.create.success.created": "Created \"{0}\" i18n content file.",
"commands.i18n.create.quickPick.title": "Create content for locale",
"commands.i18n.create.quickPick.placeHolder": "To which locale do you want to create a new content?",
"commands.i18n.createOrOpen.quickPick.title": "Open or create translation",
"commands.i18n.createOrOpen.quickPick.category.existing": "Existing translations",
"commands.i18n.createOrOpen.quickPick.action.open": "Open \"{0}\"",
"commands.i18n.createOrOpen.quickPick.category.new": "New translations",
"commands.i18n.createOrOpen.quickPick.action.create": "Create \"{0}\"",
"commands.i18n.translate.progress.title": "Translating content...",

"commands.preview.panel.title": "Preview: {0}",
"commands.preview.askUserToPickFolder.title": "Select the folder of the article to preview",

Expand Down
11 changes: 10 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2393,6 +2393,15 @@
"title": "%command.frontMatter.cache.clear%",
"category": "Front Matter"
},
{
"command": "frontMatter.i18n.createOrOpen",
"title": "%command.frontMatter.i18n.createOrOpen%",
"category": "Front Matter",
"icon": {
"light": "assets/icons/i18n-light.svg",
"dark": "assets/icons/i18n-dark.svg"
}
},
{
"command": "frontMatter.i18n.create",
"title": "%command.frontMatter.i18n.create%",
Expand Down Expand Up @@ -2448,7 +2457,7 @@
"when": "frontMatter:file:isValid == true"
},
{
"command": "frontMatter.i18n.create",
"command": "frontMatter.i18n.createOrOpen",
"group": "navigation@-127",
"when": "frontMatter:file:isValid && frontMatter:i18n:enabled"
},
Expand Down
1 change: 1 addition & 0 deletions package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
"command.frontMatter.git.sync": "Sync",
"command.frontMatter.cache.clear": "Clear cache",
"command.frontMatter.i18n.create": "Create new translation",
"command.frontMatter.i18n.createOrOpen": "Create or open translation",
"settings.configuration.title": "Front Matter: use frontmatter.json for shared team settings",
"setting.frontMatter.projects.markdownDescription": "Specify the list of projects to load in the Front Matter CMS. [Local](https://file%2B.vscode-resource.vscode-cdn.net/Users/eliostruyf/nodejs/frontmatter-test-projects/astro-blog/test.html) - [Docs](https://frontmatter.codes/docs/settings/overview#frontmatter.projects) - [View in VS Code](vscode://simpleBrowser.show?%5B%22https://frontmatter.codes/docs/settings/overview%23frontmatter.projects%22%5D)",
"setting.frontMatter.projects.items.properties.name.markdownDescription": "Specify the name of the project.",
Expand Down
188 changes: 187 additions & 1 deletion src/commands/i18n.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,14 @@
import { ProgressLocation, Uri, commands, window, workspace } from 'vscode';
import {
ProgressLocation,
QuickPickItem,
QuickPickItemKind,
QuickPickOptions,
ThemeIcon,
Uri,
commands,
window,
workspace
} from 'vscode';
import {
ArticleHelper,
ContentType,
Expand Down Expand Up @@ -32,6 +42,7 @@ export class i18n {
const subscriptions = Extension.getInstance().subscriptions;

subscriptions.push(commands.registerCommand(COMMAND_NAME.i18n.create, i18n.create));
subscriptions.push(commands.registerCommand(COMMAND_NAME.i18n.createOrOpen, i18n.createOrOpen));

i18n.clearFiles();
}
Expand Down Expand Up @@ -391,6 +402,181 @@ export class i18n {
);
}

/**
* This method handles the process of creating a new translation file if it doesn't exist,
* or opening an existing translation file if it's already present.
* @param filePath The path of the file where the new content file should be created or being switched to. Behaves like `create` if not provided.
*/
private static async createOrOpen(fileUri?: Uri | string) {
if (!fileUri) {
const filePath = ArticleHelper.getActiveFile();
fileUri = filePath ? Uri.file(filePath) : undefined;
}

if (!fileUri) {
Notifications.warning(l10n.t(LocalizationKey.commandsI18nCreateWarningNoFileSelected));
return;
}

if (typeof fileUri === 'string') {
fileUri = Uri.file(fileUri);
}

const pageFolder = await Folders.getPageFolderByFilePath(fileUri.fsPath);
if (!pageFolder || !pageFolder.localeSourcePath) {
Notifications.error(l10n.t(LocalizationKey.commandsI18nCreateErrorNoContentFolder));
return;
}

let article = await ArticleHelper.getFrontMatterByPath(fileUri.fsPath);
if (!article) {
Notifications.warning(l10n.t(LocalizationKey.commandsI18nCreateWarningNoFile));
return;
}

const contentType = await ArticleHelper.getContentType(article);
if (!contentType) {
Notifications.warning(l10n.t(LocalizationKey.commandsI18nCreateWarningNoContentType));
return;
}

const i18nSettings = await i18n.getSettings(fileUri.fsPath);
if (!i18nSettings) {
Notifications.warning(l10n.t(LocalizationKey.commandsI18nCreateWarningNoConfig));
return;
}

const sourceLocale = await i18n.getLocale(fileUri.fsPath);
if (!sourceLocale || !sourceLocale.locale) {
Notifications.warning(l10n.t(LocalizationKey.commandsI18nCreateErrorNoLocaleDefinition));
return;
}

// Determine translation file paths
const fileInfo = parse(fileUri.fsPath);
let pageBundleDir = '';
if (await ArticleHelper.isPageBundle(fileUri.fsPath)) {
const dir = ArticleHelper.getPageFolderFromBundlePath(fileUri.fsPath);
pageBundleDir = fileUri.fsPath.replace(dir, '');
pageBundleDir = join(parse(pageBundleDir).dir);
}

// Gather target locales & metadata
const translations = (await i18n.getTranslations(fileUri.fsPath)) || {};
const targetLocales = i18nSettings
.filter((i18n) => {
return i18n.path && i18n.locale !== sourceLocale.locale;
})
.map((i18n) => {
return {
...i18n,
dir: join(pageFolder.localeSourcePath!, i18n.path!, pageBundleDir),
absolutePath: join(
pageFolder.localeSourcePath!,
i18n.path!,
pageBundleDir,
fileInfo.base
),
relativePath: join(i18n.path!, pageBundleDir, fileInfo.base)
};
})
.sort((a, b) => (a.title || a.locale).localeCompare(b.title || b.locale));

if (targetLocales.length === 0) {
Notifications.warning(l10n.t(LocalizationKey.commandsI18nCreateErrorNoLocales));
return;
}

// Configure quick pick items & options
const existingTargetLocales = targetLocales.filter((i18n) => translations[i18n.locale]);
const newTargetLocales = targetLocales.filter((i18n) => !translations[i18n.locale]);
const quickPickItems: QuickPickItem[] = [
...(existingTargetLocales.length
? [
{
label: l10n.t(LocalizationKey.commandsI18nCreateOrOpenQuickPickCategoryExisting),
kind: QuickPickItemKind.Separator
},
...existingTargetLocales.map((i18n) => ({
label: i18n.title || i18n.locale,
detail: l10n.t(LocalizationKey.commandsI18nCreateOrOpenQuickPickActionOpen, i18n.relativePath)
}))
]
: []),
...(newTargetLocales.length
? [
{
label: l10n.t(LocalizationKey.commandsI18nCreateOrOpenQuickPickCategoryNew),
kind: QuickPickItemKind.Separator
},
...newTargetLocales.map((i18n) => ({
label: i18n.title || i18n.locale,
detail: `$(file-add) ${l10n.t(LocalizationKey.commandsI18nCreateOrOpenQuickPickActionCreate, i18n.relativePath)}`
}))
]
: [])
];
const quickPickOptions: QuickPickOptions = {
title: l10n.t(LocalizationKey.commandsI18nCreateOrOpenQuickPickTitle),
ignoreFocusOut: true,
matchOnDetail: true
};

const localeItem = await window.showQuickPick<QuickPickItem>(quickPickItems, quickPickOptions);
const locale = localeItem?.label;
if (!locale) {
return;
}

const targetLocale = targetLocales.find(
(i18n) => i18n.title === locale || i18n.locale === locale
);
if (!targetLocale || !targetLocale.path) {
Notifications.warning(l10n.t(LocalizationKey.commandsI18nCreateWarningNoConfig));
return;
}

// If it exists, open the translation file
if (await existsAsync(targetLocale.absolutePath)) {
await openFileInEditor(targetLocale.absolutePath);
return;
}

// If it doesn't exist, create the new translation file & update front matter
if (!(await existsAsync(targetLocale.dir))) {
await workspace.fs.createDirectory(Uri.file(targetLocale.dir));
}

article = await i18n.updateFrontMatter(
article,
fileUri.fsPath,
contentType,
sourceLocale,
targetLocale,
targetLocale.dir
);
if (sourceLocale?.locale) {
article = await i18n.translate(article, sourceLocale, targetLocale);
}

const newFileUri = Uri.file(targetLocale.absolutePath);
await workspace.fs.writeFile(
newFileUri,
Buffer.from(ArticleHelper.stringifyFrontMatter(article.content, article.data))
);

await openFileInEditor(targetLocale.absolutePath);

PagesListener.refresh();

Notifications.info(
l10n.t(
LocalizationKey.commandsI18nCreateSuccessCreated,
sourceLocale.title || sourceLocale.locale
)
);
}

/**
* Translates the given article from the source locale to the target locale using DeepL translation service.
* @param article - The article to be translated.
Expand Down
3 changes: 2 additions & 1 deletion src/constants/Extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ export const COMMAND_NAME = {

// i18n
i18n: {
create: getCommandName('i18n.create')
create: getCommandName('i18n.create'),
createOrOpen: getCommandName('i18n.createOrOpen')
},

// Project
Expand Down
20 changes: 20 additions & 0 deletions src/localization/localization.enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1884,6 +1884,26 @@ export enum LocalizationKey {
* To which locale do you want to create a new content?
*/
commandsI18nCreateQuickPickPlaceHolder = 'commands.i18n.create.quickPick.placeHolder',
/**
* Open or create translation
*/
commandsI18nCreateOrOpenQuickPickTitle = 'commands.i18n.createOrOpen.quickPick.title',
/**
* Existing translations
*/
commandsI18nCreateOrOpenQuickPickCategoryExisting = 'commands.i18n.createOrOpen.quickPick.category.existing',
/**
* Open "{0}"
*/
commandsI18nCreateOrOpenQuickPickActionOpen = 'commands.i18n.createOrOpen.quickPick.action.open',
/**
* New translations
*/
commandsI18nCreateOrOpenQuickPickCategoryNew = 'commands.i18n.createOrOpen.quickPick.category.new',
/**
* Create "{0}"
*/
commandsI18nCreateOrOpenQuickPickActionCreate = 'commands.i18n.createOrOpen.quickPick.action.create',
/**
* Translating content...
*/
Expand Down

0 comments on commit 38f128e

Please sign in to comment.