From fe60f53a7eae1d7c054d177ad526f3fc8643abf8 Mon Sep 17 00:00:00 2001 From: "aryan.mor" Date: Thu, 15 Aug 2024 17:23:37 +0300 Subject: [PATCH 1/2] Add feature to skip identical keys for specified locales Implemented logic to skip keys with identical values for specified locales in the i18next parser. Added tests to verify behavior and updated existing code to accommodate the new feature. --- CHANGELOG.md | 4 ++ README.md | 3 ++ index.d.ts | 1 + src/transform.js | 42 +++++++++++++++ test/locales/ar/test_skip_identicals.json | 7 +++ test/locales/en/test_skip_identicals.json | 7 +++ test/locales/fr/test_skip_identicals.json | 6 +++ test/parser.test.js | 64 +++++++++++++++++++++++ 8 files changed, 134 insertions(+) create mode 100644 test/locales/ar/test_skip_identicals.json create mode 100644 test/locales/en/test_skip_identicals.json create mode 100644 test/locales/fr/test_skip_identicals.json diff --git a/CHANGELOG.md b/CHANGELOG.md index 13e1c5b2..893740c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +# X.X.X + +- Add skipIdenticals option #1036 + # 9.0.2 - Fix cheerio dependency #1045 diff --git a/README.md b/README.md index ac8e5489..1c21498a 100644 --- a/README.md +++ b/README.md @@ -253,6 +253,9 @@ export default { // { // lineWidth: -1, // } + + skipIdenticals: [], + // An array of locales to skip adding entries which their keys are identical to their values or their values are empty string. } ``` diff --git a/index.d.ts b/index.d.ts index f00a68a9..1ddb1902 100644 --- a/index.d.ts +++ b/index.d.ts @@ -129,4 +129,5 @@ export interface UserConfig { resetDefaultValueLocale?: string | null i18nextOptions?: Record | null yamlOptions?: Record | null + skipIdenticals?: string[] } diff --git a/src/transform.js b/src/transform.js index 91f20084..2f0a60fe 100644 --- a/src/transform.js +++ b/src/transform.js @@ -40,6 +40,7 @@ export default class i18nTransform extends Transform { customValueTemplate: null, failOnWarnings: false, yamlOptions: null, + skipIdenticals: [], } this.options = { ...this.defaults, ...options } @@ -251,6 +252,47 @@ export default class i18nTransform extends Transform { resetValues[namespace] ) + const shouldSkipKey = (entry, skipIdenticals, local) => { + return skipIdenticals.some((skipLocale) => { + return local === skipLocale + }) + } + + const skipIdenticalsFromCatalog = ( + catalog, + skipIdenticalsLocales, + locale + ) => { + if ( + typeof skipIdenticalsLocales !== 'object' || + skipIdenticalsLocales.length === 0 + ) + return + for (const [key, value] of Object.entries(catalog)) { + if (typeof value === 'object') { + skipIdenticalsFromCatalog(value, skipIdenticalsLocales, locale) + } else { + if (shouldSkipKey(catalog, skipIdenticalsLocales, locale)) { + if (value === '') { + delete catalog[key] + } else if (value === key) { + this.warn( + '"' + + key + + '" is identical to value and you may want to remove it' + ) + } + } + } + } + } + + skipIdenticalsFromCatalog( + newCatalog, + this.options.skipIdenticals, + locale + ) + // record values to be reset // assumes that the 'default' namespace is processed first if (resetAndFlag && !resetValues[namespace]) { diff --git a/test/locales/ar/test_skip_identicals.json b/test/locales/ar/test_skip_identicals.json new file mode 100644 index 00000000..64f2d874 --- /dev/null +++ b/test/locales/ar/test_skip_identicals.json @@ -0,0 +1,7 @@ +{ + "key": "ar_translation", + "key2": { + "key3": "ar_translation" + }, + "key4": "ar_translation" +} diff --git a/test/locales/en/test_skip_identicals.json b/test/locales/en/test_skip_identicals.json new file mode 100644 index 00000000..7db2ddcd --- /dev/null +++ b/test/locales/en/test_skip_identicals.json @@ -0,0 +1,7 @@ +{ + "key": "en_translation", + "key2": { + "key3": "en_translation" + }, + "key4": "key4" +} diff --git a/test/locales/fr/test_skip_identicals.json b/test/locales/fr/test_skip_identicals.json new file mode 100644 index 00000000..1101089f --- /dev/null +++ b/test/locales/fr/test_skip_identicals.json @@ -0,0 +1,6 @@ +{ + "key": "fr_translation", + "key2": { + "key3": "fr_translation" + } +} diff --git a/test/parser.test.js b/test/parser.test.js index f056f4f8..9fe921af 100644 --- a/test/parser.test.js +++ b/test/parser.test.js @@ -803,6 +803,70 @@ describe('parser', () => { i18nextParser.end(fakeFile) }) + it('skips identical keys for specified locales', (done) => { + const i18nextParser = new i18nTransform({ + output: 'test/locales/$LOCALE/$NAMESPACE.json', + locales: ['en', 'ar', 'fr'], + skipIdenticals: ['en', 'fr'], + }) + + const fakeFile = new Vinyl({ + contents: Buffer.from( + `t('test_skip_identicals:key') + \n + t('test_skip_identicals:key2.key3') + \n + t('test_skip_identicals:key4') + \n + t('test_skip_identicals:key5')` + ), + path: 'file.js', + }) + + let enResult, arResult, frResult + i18nextParser.on('data', (file) => { + if ( + file.relative.endsWith(path.normalize('en/test_skip_identicals.json')) + ) { + enResult = JSON.parse(file.contents) + } else if ( + file.relative.endsWith(path.normalize('ar/test_skip_identicals.json')) + ) { + arResult = JSON.parse(file.contents) + } else if ( + file.relative.endsWith(path.normalize('fr/test_skip_identicals.json')) + ) { + frResult = JSON.parse(file.contents) + } + }) + + i18nextParser.once('end', () => { + assert.deepEqual(enResult, { + key: 'en_translation', + key2: { + key3: 'en_translation', + }, + }) + assert.deepEqual(arResult, { + key: 'ar_translation', + key2: { + key3: 'ar_translation', + }, + key4: 'ar_translation', + key5: '', + }) + assert.deepEqual(frResult, { + key: 'fr_translation', + key2: { + key3: 'fr_translation', + }, + }) + done() + }) + + i18nextParser.end(fakeFile) + }) + describe('options', () => { describe('resetDefaultValueLocale', () => { it('will not reset (nested) keys if a default value has not changed in the locale', (done) => { From 2a02abcf7d477ebc5755d1b7e2e41f9f15b9aba2 Mon Sep 17 00:00:00 2001 From: "aryan.mor" Date: Thu, 15 Aug 2024 18:57:40 +0300 Subject: [PATCH 2/2] Add plural support in translation skipping logic Enhanced the translation skipping functionality to handle plural forms. Added new test cases for plural translations in 'ar' and 'fr' locales. Updated helpers and transformation logic to identify and process plural keys correctly. --- src/helpers.js | 1 + src/transform.js | 7 ++++--- test/locales/ar/test_skip_identicals.json | 8 +++++++- test/locales/en/test_skip_identicals.json | 4 +++- test/locales/fr/test_skip_identicals.json | 4 +++- test/parser.test.js | 18 +++++++++++++++++- 6 files changed, 35 insertions(+), 7 deletions(-) diff --git a/src/helpers.js b/src/helpers.js index 1fd91aa1..51c6a46d 100644 --- a/src/helpers.js +++ b/src/helpers.js @@ -357,4 +357,5 @@ export { tsConfigLoader, yamlConfigLoader, unescape, + isPlural, } diff --git a/src/transform.js b/src/transform.js index 2f0a60fe..86dc99b6 100644 --- a/src/transform.js +++ b/src/transform.js @@ -12,6 +12,7 @@ import { mergeHashes, transferValues, makeDefaultSort, + isPlural, } from './helpers.js' import Parser from './parser.js' @@ -272,14 +273,14 @@ export default class i18nTransform extends Transform { if (typeof value === 'object') { skipIdenticalsFromCatalog(value, skipIdenticalsLocales, locale) } else { - if (shouldSkipKey(catalog, skipIdenticalsLocales, locale)) { + if (!isPlural(key) && shouldSkipKey(catalog, skipIdenticalsLocales, locale)) { if (value === '') { delete catalog[key] } else if (value === key) { this.warn( '"' + - key + - '" is identical to value and you may want to remove it' + key + + '" is identical to value and you may want to remove it' ) } } diff --git a/test/locales/ar/test_skip_identicals.json b/test/locales/ar/test_skip_identicals.json index 64f2d874..cdc94ef1 100644 --- a/test/locales/ar/test_skip_identicals.json +++ b/test/locales/ar/test_skip_identicals.json @@ -3,5 +3,11 @@ "key2": { "key3": "ar_translation" }, - "key4": "ar_translation" + "key4": "ar_translation", + "key6_few": "key6_few", + "key6_many": "key6_many", + "key6_one": "key6_one", + "key6_other": "key6_other", + "key6_two": "key6_two", + "key6_zero": "key6_zero" } diff --git a/test/locales/en/test_skip_identicals.json b/test/locales/en/test_skip_identicals.json index 7db2ddcd..a6fe2593 100644 --- a/test/locales/en/test_skip_identicals.json +++ b/test/locales/en/test_skip_identicals.json @@ -3,5 +3,7 @@ "key2": { "key3": "en_translation" }, - "key4": "key4" + "key4": "key4", + "key6_one": "en_Key6 one", + "key6_other": "en_Key6 other" } diff --git a/test/locales/fr/test_skip_identicals.json b/test/locales/fr/test_skip_identicals.json index 1101089f..5d4a75cc 100644 --- a/test/locales/fr/test_skip_identicals.json +++ b/test/locales/fr/test_skip_identicals.json @@ -2,5 +2,7 @@ "key": "fr_translation", "key2": { "key3": "fr_translation" - } + }, + "key6_one": "fr_Key6 one", + "key6_other": "fr_Key6 other" } diff --git a/test/parser.test.js b/test/parser.test.js index 9fe921af..ca16b35d 100644 --- a/test/parser.test.js +++ b/test/parser.test.js @@ -818,7 +818,11 @@ describe('parser', () => { \n t('test_skip_identicals:key4') \n - t('test_skip_identicals:key5')` + t('test_skip_identicals:key5') + \n + t('test_skip_identicals:key6',{count:1}) + \n + t('test_skip_identicals:key6',{count:2})` ), path: 'file.js', }) @@ -846,6 +850,9 @@ describe('parser', () => { key2: { key3: 'en_translation', }, + key4: 'key4', + key6_one: "en_Key6 one", + key6_other: "en_Key6 other" }) assert.deepEqual(arResult, { key: 'ar_translation', @@ -854,12 +861,21 @@ describe('parser', () => { }, key4: 'ar_translation', key5: '', + key6_few: "key6_few", + key6_many: "key6_many", + key6_one: "key6_one", + key6_other: "key6_other", + key6_two: "key6_two", + key6_zero: "key6_zero", }) assert.deepEqual(frResult, { key: 'fr_translation', key2: { key3: 'fr_translation', }, + key6_many: "", + key6_one: "fr_Key6 one", + key6_other: "fr_Key6 other" }) done() })