Skip to content

Commit

Permalink
Merge pull request #26 from jy95/support_custom_separator
Browse files Browse the repository at this point in the history
Support custom separator
  • Loading branch information
jy95 authored Oct 6, 2021
2 parents 8e132ae + bc6016d commit adb9db8
Show file tree
Hide file tree
Showing 28 changed files with 544 additions and 42 deletions.
13 changes: 13 additions & 0 deletions src/checks/commons/keySeparator_check.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
const KEYSEPARATOR_CHECK = async (argv: any) => {
let keySeparator = argv.keySeparator as any;
let check = [
() => keySeparator.length !== 1,
() => keySeparator === true,
].some((pred) => pred());
if (check) {
return new Error(`Option keySeparator should be a not-empty char or false`);
} else {
return true;
}
};
export default KEYSEPARATOR_CHECK;
8 changes: 7 additions & 1 deletion src/checks/diff_checks.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
// reuse check function from export command
import { FILENAME_CHECK } from './export/index';
// key separator check
import KEYSEPARATOR_CHECK from './commons/keySeparator_check';

// check if at least two paths were provided
// For that, we will use "backupKey" from backupPaths : "paths"
Expand All @@ -12,4 +14,8 @@ export const AT_LEAST_2_PATHS_CHECK = async (argv: any) => {
};

// export checks in expected order into a single array
export const CHECKS = [FILENAME_CHECK, AT_LEAST_2_PATHS_CHECK];
export const CHECKS = [
KEYSEPARATOR_CHECK,
FILENAME_CHECK,
AT_LEAST_2_PATHS_CHECK,
];
10 changes: 9 additions & 1 deletion src/checks/export/export_common_checks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ import isFunction from 'lodash/isFunction';
import isEmpty from 'lodash/isEmpty';
import uniq from 'lodash/uniq';

// key separator check
import KEYSEPARATOR_CHECK from '../commons/keySeparator_check';

// validation for filename option
export const FILENAME_CHECK = async (argv: any) => {
let filename: unknown = argv['filename'];
Expand Down Expand Up @@ -81,4 +84,9 @@ export const RESULTSFILTER_CHECK = async (argv: any) => {
};

// export checks in expected order into a single array
export const CHECKS = [FILENAME_CHECK, FILES_CHECK, RESULTSFILTER_CHECK];
export const CHECKS = [
KEYSEPARATOR_CHECK,
FILENAME_CHECK,
FILES_CHECK,
RESULTSFILTER_CHECK,
];
5 changes: 4 additions & 1 deletion src/checks/import/import_common_checks.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// lodash methodes
import uniq from 'lodash/uniq';

// key separator check
import KEYSEPARATOR_CHECK from '../commons/keySeparator_check';

// validation for locales option
export const LOCALES_CHECK = async (argv: any) => {
const locales = argv.locales as any[];
Expand All @@ -14,4 +17,4 @@ export const LOCALES_CHECK = async (argv: any) => {
};

// export checks in expected order into a single array
export const CHECKS = [LOCALES_CHECK];
export const CHECKS = [KEYSEPARATOR_CHECK, LOCALES_CHECK];
1 change: 1 addition & 0 deletions src/cmds/diff.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ export const builder = function (y: Argv) {
new CommonDiffYargsBuilder(y)
.addFilenameOption()
.addOutputDirOption()
.addKeySeparatorOption()
.addOutputFormatOption()
.addFilesOption()
.addSettingConfig()
Expand Down
26 changes: 18 additions & 8 deletions src/cmds/diff/detectChanges.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,12 @@ import type {
DelOperation,
PutOperation,
} from '../../types/diffTypes';

// Own methods
import getLeavesPathes from '../../commons/getLeavesPathes';
import get from '../../commons/enhancedGet';

// lodash method
import get from 'lodash/get';
import intersection from 'lodash/intersection';
import isEqual from 'lodash/isEqual';
import difference from 'lodash/difference';
Expand All @@ -24,7 +26,8 @@ function createChangeOperation(
technicalKey: string,
op: ChangesOps,
file1: fileParam,
file2: fileParam
file2: fileParam,
keySeparator: string | false
): ChangeOperations {
// common part
let obj: CommonChangeOperation = {
Expand All @@ -37,13 +40,15 @@ function createChangeOperation(
if ([ChangesOps.DEL, ChangesOps.PUT].some((o) => o === op)) {
(obj as DelOperation | PutOperation).oldValue = get(
file1.obj,
technicalKey
technicalKey,
keySeparator
);
}
if ([ChangesOps.ADD, ChangesOps.PUT].some((o) => o === op)) {
(obj as AddOperation | PutOperation).newValue = get(
file2.obj,
technicalKey
technicalKey,
keySeparator
);
}
// return result
Expand All @@ -55,6 +60,7 @@ export default function detectChanges(
argv: CommonDiffArguments
): ChangeOperations[] {
let result: ChangeOperations[] = [];
let keySeparator: string | false = argv.keySeparator;

// Fetch keys
let files: fileParam[] = argv.files.map((file, idx) => ({
Expand All @@ -78,26 +84,30 @@ export default function detectChanges(
// Computes changes of values
let sameKeys = intersection(file1.keys, file2.keys);
let modifiedKeys = sameKeys.filter(
(key) => !isEqual(get(file1.obj, key), get(file2.obj, key))
(key) =>
!isEqual(
get(file1.obj, key, keySeparator),
get(file2.obj, key, keySeparator)
)
);

result.push(
...modifiedKeys.map((key) =>
createChangeOperation(key, ChangesOps.PUT, file1, file2)
createChangeOperation(key, ChangesOps.PUT, file1, file2, keySeparator)
)
);

// Computes deleted keys
result.push(
...difference(file1.keys, file2.keys).map((key) =>
createChangeOperation(key, ChangesOps.DEL, file1, file2)
createChangeOperation(key, ChangesOps.DEL, file1, file2, keySeparator)
)
);

// Computes new keys
result.push(
...difference(file2.keys, file1.keys).map((key) =>
createChangeOperation(key, ChangesOps.ADD, file1, file2)
createChangeOperation(key, ChangesOps.ADD, file1, file2, keySeparator)
)
);
}
Expand Down
30 changes: 20 additions & 10 deletions src/cmds/export_cmds/export_commons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import fs, { PathLike } from 'fs';
// lodash methodes
import groupBy from 'lodash/groupBy';
import flattenDeep from 'lodash/flattenDeep';
import get from 'lodash/get';

// "Enhanced get"
import get from '../../commons/enhancedGet';

// For typings
import {
Expand Down Expand Up @@ -77,7 +79,11 @@ export function merge_i18n_files(
return new Promise((resolve, reject) => {
Promise
// Read files and convert them to useful obj
.all(Object.entries(argv.files).map((entry) => readFile(entry)))
.all(
Object.entries(argv.files).map((entry) =>
readFile(entry, argv.keySeparator)
)
)
// merge results
.then((results) => mergeResults(results))
.then((data) => resolve(data))
Expand All @@ -88,27 +94,31 @@ export function merge_i18n_files(
// merge_i18n_files sub functions

// read file and turning into a useful array of objects
function readFile([locale, file_path]: [
string,
PathLike
]): Promise<I18N_Result> {
function readFile(
[locale, file_path]: [string, PathLike],
keySeparator: string | false
): Promise<I18N_Result> {
return new Promise((resolve, reject) => {
fs.promises
.readFile(file_path, 'utf8')
.then((jsonData) => Promise.resolve(JSON.parse(jsonData)))
.then((json) => i18n_to_result_format(json, locale))
.then((json) => i18n_to_result_format(json, locale, keySeparator))
.then((result) => resolve(result))
.catch(/* istanbul ignore next */ (err) => reject(err));
});
}

// turns i18n object to usable format
function i18n_to_result_format(obj: I18N_Object, locale: string): I18N_Result {
let leafPaths = getLeavesPathes(obj);
function i18n_to_result_format(
obj: I18N_Object,
locale: string,
keySeparator: string | false
): I18N_Result {
let leafPaths = getLeavesPathes(obj, keySeparator);
return leafPaths.map((leafPath) => ({
locale: locale,
technical_key: leafPath,
label: get(obj, leafPath) as string,
label: get(obj, leafPath, keySeparator) as string,
}));
}

Expand Down
1 change: 1 addition & 0 deletions src/cmds/export_cmds/export_csv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ export const builder = function (y: Argv) {
.addFilenameOption()
.addOutputDirOption()
.addSettingConfig()
.addKeySeparatorOption()
.addColumnsOption()
.addDelimiterOption()
.addRowDelimiterOption()
Expand Down
1 change: 1 addition & 0 deletions src/cmds/export_cmds/export_xlsx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ export const builder = function (y: Argv) {
.addFilenameOption()
.addOutputDirOption()
.addSettingConfig()
.addKeySeparatorOption()
.addColumnsOption()
.addWorksheetCustomizerOption()
.addWorksheetNameOption()
Expand Down
16 changes: 11 additions & 5 deletions src/cmds/import_cmds/import_commons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ import fs from 'fs';
import { resolve as pathResolve } from 'path';

// lodash methodes
import set from 'lodash/set';
import groupBy from 'lodash/groupBy';

// Own method
import set from '../../commons/enhancedSet';

// For typings
import {
CommonImportArguments,
Expand Down Expand Up @@ -66,15 +68,16 @@ export function generate_i18n_filepaths(argv: CommonImportArguments) {
// extractedTranslation[] to i18n file(s)
export function extractedTranslations_to_i18n_files(
files: { [x: string]: string },
translations: extractedTranslation[]
translations: extractedTranslation[],
keySeparator: string | false
) {
let groupBy_locales = groupBy(translations, 'locale');
return Promise.all(
Object.entries(groupBy_locales).map(([locale, translations]) =>
write_new_i18n_file(
locale,
files[locale],
translations_2_i18n_object(translations)
translations_2_i18n_object(translations, keySeparator)
)
)
);
Expand All @@ -99,10 +102,13 @@ function write_new_i18n_file(
}

// Turns array for a given lang into a i18n js object
function translations_2_i18n_object(translations: extractedTranslation[]) {
function translations_2_i18n_object(
translations: extractedTranslation[],
keySeparator: string | false
) {
let result = {};
translations.forEach((item) => {
set(result, item['technical_key'], item['label']);
set(result, item['technical_key'], item['label'], keySeparator);
});
return result;
}
7 changes: 6 additions & 1 deletion src/cmds/import_cmds/import_csv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ export const builder = function (y: Argv) {
.addInputOption()
.addLocalesOption()
.addOutputDirOption(true)
.addKeySeparatorOption()
.addSuffixOption()
.addColumnsOption()
.addDelimiterOption()
Expand All @@ -100,7 +101,11 @@ export const handler = async function (argv: CSVImportArguments) {
try {
const translations = await csv_2_translation_objects(argv);
const files = generate_i18n_filepaths(argv);
await extractedTranslations_to_i18n_files(files, translations);
await extractedTranslations_to_i18n_files(
files,
translations,
argv.keySeparator
);
console.log('Successfully exported found locale(s) to i18n json file(s)');
return Promise.resolve(undefined);
} catch (error) {
Expand Down
7 changes: 6 additions & 1 deletion src/cmds/import_cmds/import_xlsx.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export const builder = function (y: Argv) {
.addInputOption()
.addLocalesOption()
.addOutputDirOption(true)
.addKeySeparatorOption()
.addSuffixOption()
.addColumnsOption()
.addSettingConfig()
Expand All @@ -59,7 +60,11 @@ export const handler = async function (argv: XLSXImportArguments) {
try {
const translations = await xlsx_2_translation_objects(argv);
const files = generate_i18n_filepaths(argv);
await extractedTranslations_to_i18n_files(files, translations);
await extractedTranslations_to_i18n_files(
files,
translations,
argv.keySeparator
);
console.log('Successfully exported found locale(s) to i18n json file(s)');
return Promise.resolve(undefined);
} catch (error) {
Expand Down
15 changes: 15 additions & 0 deletions src/commons/commandBuilder.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { readFileSync } from 'fs';
import { extname, resolve } from 'path';
import { parseUnknownToFalse } from '../middlewares/middlewares';

// For typing
// eslint-disable-next-line
Expand Down Expand Up @@ -37,6 +38,20 @@ export default class CommandBuilder {
return this;
}

addKeySeparatorOption() {
this.y = this.y
.option('keySeparator', {
type: 'string',
alias: 'ks',
describe:
'Char to separate i18n keys. If working with flat JSON, set this to false',
default: '.',
})
// parse false values
.middleware(parseUnknownToFalse('keySeparator'), true);
return this;
}

build() {
return this.y;
}
Expand Down
18 changes: 18 additions & 0 deletions src/commons/enhancedGet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// lodash methods
import get from 'lodash/get';

// "Enhance" Lodash get, to deal with custom separator
export default function enhancedGet(
obj: any,
key: string,
keySeparator: string | false
) {
// compute path that use dot (or custom) separator + square brack notation
let path = keySeparator
? key
// handle square brack notation - eg: a[10] should be translated as a.10
.replace(/\[(\d+)\]/g, `${keySeparator}$1`)
.split(keySeparator)
: [key];
return get(obj, path);
}
19 changes: 19 additions & 0 deletions src/commons/enhancedSet.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// lodash methods
import set from 'lodash/set';

// "Enhance" Lodash set, to deal with custom separator
export default function enhancedSet(
obj: any,
key: string,
val: any,
keySeparator: string | false
) {
// compute path that use dot (or custom) separator + square brack notation
let path = keySeparator
? key
// handle square brack notation - eg: a[10] should be translated as a.10
.replace(/\[(\d+)\]/g, `${keySeparator}$1`)
.split(keySeparator)
: [key];
return set(obj, path, val);
}
Loading

0 comments on commit adb9db8

Please sign in to comment.