@elementor/extract-i18n-wordpress-expressions-webpack-plugin 0.3.1 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,35 +3,31 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
- ## [0.3.1](https://github.com/elementor/elementor-packages/compare/@elementor/extract-i18n-wordpress-expressions-webpack-plugin@0.3.0...@elementor/extract-i18n-wordpress-expressions-webpack-plugin@0.3.1) (2023-11-07)
6
+ ## [0.3.3](https://github.com/elementor/elementor-packages/compare/@elementor/extract-i18n-wordpress-expressions-webpack-plugin@0.3.2...@elementor/extract-i18n-wordpress-expressions-webpack-plugin@0.3.3) (2024-08-05)
7
7
 
8
- **Note:** Version bump only for package @elementor/extract-i18n-wordpress-expressions-webpack-plugin
8
+ ### Bug Fixes
9
9
 
10
+ - publish only necessary files to npm ([#226](https://github.com/elementor/elementor-packages/issues/226)) ([d808e2f](https://github.com/elementor/elementor-packages/commit/d808e2f60eb7ca2d7b8560d0b79c0e62c2f969a8))
10
11
 
12
+ ## [0.3.2](https://github.com/elementor/elementor-packages/compare/@elementor/extract-i18n-wordpress-expressions-webpack-plugin@0.3.1...@elementor/extract-i18n-wordpress-expressions-webpack-plugin@0.3.2) (2024-07-16)
11
13
 
14
+ **Note:** Version bump only for package @elementor/extract-i18n-wordpress-expressions-webpack-plugin
12
15
 
16
+ ## [0.3.1](https://github.com/elementor/elementor-packages/compare/@elementor/extract-i18n-wordpress-expressions-webpack-plugin@0.3.0...@elementor/extract-i18n-wordpress-expressions-webpack-plugin@0.3.1) (2023-11-07)
13
17
 
14
- # [0.3.0](https://github.com/elementor/elementor-packages/compare/@elementor/extract-i18n-wordpress-expressions-webpack-plugin@0.2.2...@elementor/extract-i18n-wordpress-expressions-webpack-plugin@0.3.0) (2023-09-12)
18
+ **Note:** Version bump only for package @elementor/extract-i18n-wordpress-expressions-webpack-plugin
15
19
 
20
+ # [0.3.0](https://github.com/elementor/elementor-packages/compare/@elementor/extract-i18n-wordpress-expressions-webpack-plugin@0.2.2...@elementor/extract-i18n-wordpress-expressions-webpack-plugin@0.3.0) (2023-09-12)
16
21
 
17
22
  ### Features
18
23
 
19
- * **i18n-webpack:** changed the way it extracts expressions ([#117](https://github.com/elementor/elementor-packages/issues/117)) ([5be687d](https://github.com/elementor/elementor-packages/commit/5be687d57ca9d0c335b9803aea12cdacc14f8202))
20
-
21
-
22
-
23
-
24
+ - **i18n-webpack:** changed the way it extracts expressions ([#117](https://github.com/elementor/elementor-packages/issues/117)) ([5be687d](https://github.com/elementor/elementor-packages/commit/5be687d57ca9d0c335b9803aea12cdacc14f8202))
24
25
 
25
26
  ## 0.2.2 (2023-08-31)
26
27
 
27
-
28
28
  ### Bug Fixes
29
29
 
30
- * **i18n-plugin:** typo in package name [ED-11227] ([#109](https://github.com/elementor/elementor-packages/issues/109)) ([e2adcbf](https://github.com/elementor/elementor-packages/commit/e2adcbf988019493d1a72404b4fe62eeef2f6a59))
31
-
32
-
33
-
34
-
30
+ - **i18n-plugin:** typo in package name [ED-11227] ([#109](https://github.com/elementor/elementor-packages/issues/109)) ([e2adcbf](https://github.com/elementor/elementor-packages/commit/e2adcbf988019493d1a72404b4fe62eeef2f6a59))
35
31
 
36
32
  ## 0.2.1 (2023-07-02)
37
33
 
package/dist/index.js CHANGED
@@ -49,7 +49,7 @@ var COMMENTS_REGEXPS = [
49
49
  ];
50
50
  var TRANSLATIONS_REGEXPS = [
51
51
  // Matches translation functions: `__('Hello', 'elementor')`, `_n('Me', 'Us', 2, 'elementor-pro')`.
52
- /\b_(?:_|n|nx|x)\(.*?,\s*(?<c>['"`])[\w-]+\k<c>\s*?\)/sg
52
+ /\b_(?:_|n|nx|x)\(.*?,\s*(?<c>['"`])[\w-]+\k<c>\s*?\)/gs
53
53
  ];
54
54
  function createStringsFilePath(path2, suffix = ".strings.js") {
55
55
  return path2.replace(/(\.min)?\.js$/i, suffix);
@@ -103,9 +103,7 @@ var ExtractI18nWordpressExpressionsWebpackPlugin = class {
103
103
  const entries = this.getEntries(compilation);
104
104
  await Promise.all(
105
105
  entries.map(async (entry) => {
106
- const fileContents = await getFilesContents(
107
- await getFilesPaths(entry.pattern)
108
- );
106
+ const fileContents = await getFilesContents(await getFilesPaths(entry.pattern));
109
107
  const entryContent = generateStringsFileContent(fileContents);
110
108
  await fs2.promises.writeFile(entry.path, entryContent);
111
109
  })
@@ -131,10 +129,7 @@ var ExtractI18nWordpressExpressionsWebpackPlugin = class {
131
129
  id,
132
130
  chunk,
133
131
  path: path.join(basePath, filePath),
134
- pattern: this.options.pattern(
135
- path.resolve(process.cwd(), entrypoint.origins[0].request),
136
- id
137
- )
132
+ pattern: this.options.pattern(path.resolve(process.cwd(), entrypoint.origins[0].request), id)
138
133
  };
139
134
  }).filter(Boolean);
140
135
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/plugin.ts","../src/utils.ts"],"sourcesContent":["export { default as ExtractI18nWordpressExpressionsWebpackPlugin } from './plugin';\n","import * as path from 'path';\nimport * as fs from 'fs';\nimport { Compilation, Compiler } from 'webpack';\nimport { EntrySettings } from './types';\nimport {\n\tcreateStringsFilePath,\n\tgenerateStringsFileContent,\n\tgetFilesContents,\n\tgetFilesPaths,\n} from './utils';\n\ntype Options = {\n\tpattern: ( entryPath: string, entryId: string ) => string;\n}\n\nexport default class ExtractI18nWordpressExpressionsWebpackPlugin {\n\toptions: Options;\n\n\tconstructor( options: Options ) {\n\t\tthis.options = options;\n\t}\n\n\tapply( compiler: Compiler ) {\n\t\tcompiler.hooks.afterEmit.tapPromise( this.constructor.name, async ( compilation ) => {\n\t\t\tconst entries = this.getEntries( compilation );\n\n\t\t\tawait Promise.all(\n\t\t\t\tentries.map( async ( entry ) => {\n\t\t\t\t\tconst fileContents = await getFilesContents(\n\t\t\t\t\t\tawait getFilesPaths( entry.pattern )\n\t\t\t\t\t);\n\n\t\t\t\t\tconst entryContent = generateStringsFileContent( fileContents );\n\n\t\t\t\t\t// Writing manually instead of using `chunk.files.add()` in order to avoid passing\n\t\t\t\t\t// the file through the loaders (transpilers, minifiers, etc.).\n\t\t\t\t\tawait fs.promises.writeFile( entry.path, entryContent );\n\t\t\t\t} )\n\t\t\t);\n\t\t} );\n\t}\n\n\tgetEntries( compilation: Compilation ) {\n\t\treturn [ ...compilation.entrypoints ]\n\t\t\t.map( ( [ id, entrypoint ] ) => {\n\t\t\t\tconst chunk = entrypoint.chunks.find( ( { name } ) => name === id );\n\n\t\t\t\tif ( ! chunk ) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\tconst chunkJSFile = [ ...chunk.files ].find( ( f ) => /\\.(js|ts)$/i.test( f ) );\n\n\t\t\t\tif ( ! chunkJSFile ) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\tconst { path: basePath } = compilation.options.output;\n\n\t\t\t\tif ( ! basePath ) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\tconst filePath = createStringsFilePath( compilation.getPath( '[file]', { filename: chunkJSFile } ) );\n\n\t\t\t\treturn {\n\t\t\t\t\tid,\n\t\t\t\t\tchunk,\n\t\t\t\t\tpath: path.join( basePath, filePath ),\n\t\t\t\t\tpattern: this.options.pattern(\n\t\t\t\t\t\tpath.resolve( process.cwd(), entrypoint.origins[ 0 ].request ),\n\t\t\t\t\t\tid\n\t\t\t\t\t),\n\t\t\t\t};\n\t\t\t} )\n\t\t\t.filter( Boolean ) as EntrySettings[];\n\t}\n}\n","import { TranslationCallExpression } from './types';\nimport { glob } from 'glob';\nimport * as fs from 'fs';\n\nconst COMMENTS_REGEXPS = [\n\t// Matches translators comment block: `/* translators: %s */`.\n\t/\\/\\*[\\t ]*translators:.*\\*\\//gm,\n\t// Matches translators inline comment: `// translators: %s`.\n\t/(\\/\\/)[\\t ]*translators:[^\\r\\n]*/gm,\n] as const;\n\nconst TRANSLATIONS_REGEXPS = [\n\t// Matches translation functions: `__('Hello', 'elementor')`, `_n('Me', 'Us', 2, 'elementor-pro')`.\n\t/\\b_(?:_|n|nx|x)\\(.*?,\\s*(?<c>['\"`])[\\w-]+\\k<c>\\s*?\\)/sg,\n] as const;\n\nexport function createStringsFilePath( path: string, suffix = '.strings.js' ) {\n\treturn path.replace( /(\\.min)?\\.js$/i, suffix );\n}\n\nexport function getFilesPaths( pattern: string ) {\n\treturn glob( pattern, {\n\t\tignore: {\n\t\t\tignored: ( p ) => ! ( /\\.(js|ts|jsx|tsx)$/.test( p.name ) ),\n\t\t\tchildrenIgnored: ( p ) => p.isNamed( '__tests__' ) || p.isNamed( '__mocks__' ),\n\t\t},\n\n\t\t/**\n\t\t * Fix for Windows paths escaping.\n\t\t * Note: This means we don't support paths with special character (like `*`,`?`, etc.)\n\t\t * and only allow patterns that are constructed using `path.join()` or `path.resolve()`.\n\t\t *\n\t\t * @see https://github.com/isaacs/node-glob#options\n\t\t * @see https://github.com/isaacs/node-glob#windows\n\t\t * @see https://github.com/isaacs/node-glob/issues/212#issuecomment-1449062925\n\t\t */\n\t\twindowsPathsNoEscape: true,\n\t} );\n}\n\nexport function getFilesContents( paths: string[] ) {\n\treturn Promise.all( paths.map( ( filePath ) => fs.promises.readFile( filePath, 'utf-8' ) ) );\n}\n\nexport function generateStringsFileContent( contents: string[] ) {\n\treturn contents\n\t\t.map( ( content, ) => extractExpressions( content ) )\n\t\t.flat()\n\t\t// Add a semicolon when needed.\n\t\t.map( ( expr ) => `${ expr.value }${ expr.type === 'comment' ? '' : ';' }` )\n\t\t// Join all the expressions to a single string with line-breaks between them.\n\t\t.join( '\\n' );\n}\n\nfunction extractExpressions( content: string ): TranslationCallExpression[] {\n\tconst expressions: TranslationCallExpression[] = [];\n\n\t[ ...TRANSLATIONS_REGEXPS, ...COMMENTS_REGEXPS ].forEach( ( regexp ) => {\n\t\t[ ...content.matchAll( regexp ) ].forEach( ( res ) => {\n\t\t\texpressions.push( {\n\t\t\t\ttype: COMMENTS_REGEXPS.includes( regexp ) ? 'comment' : 'call-expression',\n\t\t\t\tindex: res.index || 0,\n\t\t\t\tvalue: res[ 0 ],\n\t\t\t} );\n\t\t} );\n\t} );\n\n\t// Sort by the index it was found in the file based on the regexp (and not by the order it was added to the array).\n\treturn expressions.sort( ( a, b ) => a.index - b.index );\n}\n"],"mappings":"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","names":["fs","path"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/plugin.ts","../src/utils.ts"],"sourcesContent":["export { default as ExtractI18nWordpressExpressionsWebpackPlugin } from './plugin';\n","import * as path from 'path';\nimport * as fs from 'fs';\nimport { Compilation, Compiler } from 'webpack';\nimport { EntrySettings } from './types';\nimport { createStringsFilePath, generateStringsFileContent, getFilesContents, getFilesPaths } from './utils';\n\ntype Options = {\n\tpattern: ( entryPath: string, entryId: string ) => string;\n};\n\nexport default class ExtractI18nWordpressExpressionsWebpackPlugin {\n\toptions: Options;\n\n\tconstructor( options: Options ) {\n\t\tthis.options = options;\n\t}\n\n\tapply( compiler: Compiler ) {\n\t\tcompiler.hooks.afterEmit.tapPromise( this.constructor.name, async ( compilation ) => {\n\t\t\tconst entries = this.getEntries( compilation );\n\n\t\t\tawait Promise.all(\n\t\t\t\tentries.map( async ( entry ) => {\n\t\t\t\t\tconst fileContents = await getFilesContents( await getFilesPaths( entry.pattern ) );\n\n\t\t\t\t\tconst entryContent = generateStringsFileContent( fileContents );\n\n\t\t\t\t\t// Writing manually instead of using `chunk.files.add()` in order to avoid passing\n\t\t\t\t\t// the file through the loaders (transpilers, minifiers, etc.).\n\t\t\t\t\tawait fs.promises.writeFile( entry.path, entryContent );\n\t\t\t\t} )\n\t\t\t);\n\t\t} );\n\t}\n\n\tgetEntries( compilation: Compilation ) {\n\t\treturn [ ...compilation.entrypoints ]\n\t\t\t.map( ( [ id, entrypoint ] ) => {\n\t\t\t\tconst chunk = entrypoint.chunks.find( ( { name } ) => name === id );\n\n\t\t\t\tif ( ! chunk ) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\tconst chunkJSFile = [ ...chunk.files ].find( ( f ) => /\\.(js|ts)$/i.test( f ) );\n\n\t\t\t\tif ( ! chunkJSFile ) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\tconst { path: basePath } = compilation.options.output;\n\n\t\t\t\tif ( ! basePath ) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\tconst filePath = createStringsFilePath( compilation.getPath( '[file]', { filename: chunkJSFile } ) );\n\n\t\t\t\treturn {\n\t\t\t\t\tid,\n\t\t\t\t\tchunk,\n\t\t\t\t\tpath: path.join( basePath, filePath ),\n\t\t\t\t\tpattern: this.options.pattern( path.resolve( process.cwd(), entrypoint.origins[ 0 ].request ), id ),\n\t\t\t\t};\n\t\t\t} )\n\t\t\t.filter( Boolean ) as EntrySettings[];\n\t}\n}\n","import { TranslationCallExpression } from './types';\nimport { glob } from 'glob';\nimport * as fs from 'fs';\n\nconst COMMENTS_REGEXPS = [\n\t// Matches translators comment block: `/* translators: %s */`.\n\t/\\/\\*[\\t ]*translators:.*\\*\\//gm,\n\t// Matches translators inline comment: `// translators: %s`.\n\t/(\\/\\/)[\\t ]*translators:[^\\r\\n]*/gm,\n] as const;\n\nconst TRANSLATIONS_REGEXPS = [\n\t// Matches translation functions: `__('Hello', 'elementor')`, `_n('Me', 'Us', 2, 'elementor-pro')`.\n\t/\\b_(?:_|n|nx|x)\\(.*?,\\s*(?<c>['\"`])[\\w-]+\\k<c>\\s*?\\)/gs,\n] as const;\n\nexport function createStringsFilePath( path: string, suffix = '.strings.js' ) {\n\treturn path.replace( /(\\.min)?\\.js$/i, suffix );\n}\n\nexport function getFilesPaths( pattern: string ) {\n\treturn glob( pattern, {\n\t\tignore: {\n\t\t\tignored: ( p ) => ! /\\.(js|ts|jsx|tsx)$/.test( p.name ),\n\t\t\tchildrenIgnored: ( p ) => p.isNamed( '__tests__' ) || p.isNamed( '__mocks__' ),\n\t\t},\n\n\t\t/**\n\t\t * Fix for Windows paths escaping.\n\t\t * Note: This means we don't support paths with special character (like `*`,`?`, etc.)\n\t\t * and only allow patterns that are constructed using `path.join()` or `path.resolve()`.\n\t\t *\n\t\t * @see https://github.com/isaacs/node-glob#options\n\t\t * @see https://github.com/isaacs/node-glob#windows\n\t\t * @see https://github.com/isaacs/node-glob/issues/212#issuecomment-1449062925\n\t\t */\n\t\twindowsPathsNoEscape: true,\n\t} );\n}\n\nexport function getFilesContents( paths: string[] ) {\n\treturn Promise.all( paths.map( ( filePath ) => fs.promises.readFile( filePath, 'utf-8' ) ) );\n}\n\nexport function generateStringsFileContent( contents: string[] ) {\n\treturn (\n\t\tcontents\n\t\t\t.map( ( content ) => extractExpressions( content ) )\n\t\t\t.flat()\n\t\t\t// Add a semicolon when needed.\n\t\t\t.map( ( expr ) => `${ expr.value }${ expr.type === 'comment' ? '' : ';' }` )\n\t\t\t// Join all the expressions to a single string with line-breaks between them.\n\t\t\t.join( '\\n' )\n\t);\n}\n\nfunction extractExpressions( content: string ): TranslationCallExpression[] {\n\tconst expressions: TranslationCallExpression[] = [];\n\n\t[ ...TRANSLATIONS_REGEXPS, ...COMMENTS_REGEXPS ].forEach( ( regexp ) => {\n\t\t[ ...content.matchAll( regexp ) ].forEach( ( res ) => {\n\t\t\texpressions.push( {\n\t\t\t\ttype: COMMENTS_REGEXPS.includes( regexp ) ? 'comment' : 'call-expression',\n\t\t\t\tindex: res.index || 0,\n\t\t\t\tvalue: res[ 0 ],\n\t\t\t} );\n\t\t} );\n\t} );\n\n\t// Sort by the index it was found in the file based on the regexp (and not by the order it was added to the array).\n\treturn expressions.sort( ( a, b ) => a.index - b.index );\n}\n"],"mappings":"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","names":["fs","path"]}
package/dist/index.mjs CHANGED
@@ -13,7 +13,7 @@ var COMMENTS_REGEXPS = [
13
13
  ];
14
14
  var TRANSLATIONS_REGEXPS = [
15
15
  // Matches translation functions: `__('Hello', 'elementor')`, `_n('Me', 'Us', 2, 'elementor-pro')`.
16
- /\b_(?:_|n|nx|x)\(.*?,\s*(?<c>['"`])[\w-]+\k<c>\s*?\)/sg
16
+ /\b_(?:_|n|nx|x)\(.*?,\s*(?<c>['"`])[\w-]+\k<c>\s*?\)/gs
17
17
  ];
18
18
  function createStringsFilePath(path2, suffix = ".strings.js") {
19
19
  return path2.replace(/(\.min)?\.js$/i, suffix);
@@ -67,9 +67,7 @@ var ExtractI18nWordpressExpressionsWebpackPlugin = class {
67
67
  const entries = this.getEntries(compilation);
68
68
  await Promise.all(
69
69
  entries.map(async (entry) => {
70
- const fileContents = await getFilesContents(
71
- await getFilesPaths(entry.pattern)
72
- );
70
+ const fileContents = await getFilesContents(await getFilesPaths(entry.pattern));
73
71
  const entryContent = generateStringsFileContent(fileContents);
74
72
  await fs2.promises.writeFile(entry.path, entryContent);
75
73
  })
@@ -95,10 +93,7 @@ var ExtractI18nWordpressExpressionsWebpackPlugin = class {
95
93
  id,
96
94
  chunk,
97
95
  path: path.join(basePath, filePath),
98
- pattern: this.options.pattern(
99
- path.resolve(process.cwd(), entrypoint.origins[0].request),
100
- id
101
- )
96
+ pattern: this.options.pattern(path.resolve(process.cwd(), entrypoint.origins[0].request), id)
102
97
  };
103
98
  }).filter(Boolean);
104
99
  }
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/plugin.ts","../src/utils.ts"],"sourcesContent":["import * as path from 'path';\nimport * as fs from 'fs';\nimport { Compilation, Compiler } from 'webpack';\nimport { EntrySettings } from './types';\nimport {\n\tcreateStringsFilePath,\n\tgenerateStringsFileContent,\n\tgetFilesContents,\n\tgetFilesPaths,\n} from './utils';\n\ntype Options = {\n\tpattern: ( entryPath: string, entryId: string ) => string;\n}\n\nexport default class ExtractI18nWordpressExpressionsWebpackPlugin {\n\toptions: Options;\n\n\tconstructor( options: Options ) {\n\t\tthis.options = options;\n\t}\n\n\tapply( compiler: Compiler ) {\n\t\tcompiler.hooks.afterEmit.tapPromise( this.constructor.name, async ( compilation ) => {\n\t\t\tconst entries = this.getEntries( compilation );\n\n\t\t\tawait Promise.all(\n\t\t\t\tentries.map( async ( entry ) => {\n\t\t\t\t\tconst fileContents = await getFilesContents(\n\t\t\t\t\t\tawait getFilesPaths( entry.pattern )\n\t\t\t\t\t);\n\n\t\t\t\t\tconst entryContent = generateStringsFileContent( fileContents );\n\n\t\t\t\t\t// Writing manually instead of using `chunk.files.add()` in order to avoid passing\n\t\t\t\t\t// the file through the loaders (transpilers, minifiers, etc.).\n\t\t\t\t\tawait fs.promises.writeFile( entry.path, entryContent );\n\t\t\t\t} )\n\t\t\t);\n\t\t} );\n\t}\n\n\tgetEntries( compilation: Compilation ) {\n\t\treturn [ ...compilation.entrypoints ]\n\t\t\t.map( ( [ id, entrypoint ] ) => {\n\t\t\t\tconst chunk = entrypoint.chunks.find( ( { name } ) => name === id );\n\n\t\t\t\tif ( ! chunk ) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\tconst chunkJSFile = [ ...chunk.files ].find( ( f ) => /\\.(js|ts)$/i.test( f ) );\n\n\t\t\t\tif ( ! chunkJSFile ) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\tconst { path: basePath } = compilation.options.output;\n\n\t\t\t\tif ( ! basePath ) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\tconst filePath = createStringsFilePath( compilation.getPath( '[file]', { filename: chunkJSFile } ) );\n\n\t\t\t\treturn {\n\t\t\t\t\tid,\n\t\t\t\t\tchunk,\n\t\t\t\t\tpath: path.join( basePath, filePath ),\n\t\t\t\t\tpattern: this.options.pattern(\n\t\t\t\t\t\tpath.resolve( process.cwd(), entrypoint.origins[ 0 ].request ),\n\t\t\t\t\t\tid\n\t\t\t\t\t),\n\t\t\t\t};\n\t\t\t} )\n\t\t\t.filter( Boolean ) as EntrySettings[];\n\t}\n}\n","import { TranslationCallExpression } from './types';\nimport { glob } from 'glob';\nimport * as fs from 'fs';\n\nconst COMMENTS_REGEXPS = [\n\t// Matches translators comment block: `/* translators: %s */`.\n\t/\\/\\*[\\t ]*translators:.*\\*\\//gm,\n\t// Matches translators inline comment: `// translators: %s`.\n\t/(\\/\\/)[\\t ]*translators:[^\\r\\n]*/gm,\n] as const;\n\nconst TRANSLATIONS_REGEXPS = [\n\t// Matches translation functions: `__('Hello', 'elementor')`, `_n('Me', 'Us', 2, 'elementor-pro')`.\n\t/\\b_(?:_|n|nx|x)\\(.*?,\\s*(?<c>['\"`])[\\w-]+\\k<c>\\s*?\\)/sg,\n] as const;\n\nexport function createStringsFilePath( path: string, suffix = '.strings.js' ) {\n\treturn path.replace( /(\\.min)?\\.js$/i, suffix );\n}\n\nexport function getFilesPaths( pattern: string ) {\n\treturn glob( pattern, {\n\t\tignore: {\n\t\t\tignored: ( p ) => ! ( /\\.(js|ts|jsx|tsx)$/.test( p.name ) ),\n\t\t\tchildrenIgnored: ( p ) => p.isNamed( '__tests__' ) || p.isNamed( '__mocks__' ),\n\t\t},\n\n\t\t/**\n\t\t * Fix for Windows paths escaping.\n\t\t * Note: This means we don't support paths with special character (like `*`,`?`, etc.)\n\t\t * and only allow patterns that are constructed using `path.join()` or `path.resolve()`.\n\t\t *\n\t\t * @see https://github.com/isaacs/node-glob#options\n\t\t * @see https://github.com/isaacs/node-glob#windows\n\t\t * @see https://github.com/isaacs/node-glob/issues/212#issuecomment-1449062925\n\t\t */\n\t\twindowsPathsNoEscape: true,\n\t} );\n}\n\nexport function getFilesContents( paths: string[] ) {\n\treturn Promise.all( paths.map( ( filePath ) => fs.promises.readFile( filePath, 'utf-8' ) ) );\n}\n\nexport function generateStringsFileContent( contents: string[] ) {\n\treturn contents\n\t\t.map( ( content, ) => extractExpressions( content ) )\n\t\t.flat()\n\t\t// Add a semicolon when needed.\n\t\t.map( ( expr ) => `${ expr.value }${ expr.type === 'comment' ? '' : ';' }` )\n\t\t// Join all the expressions to a single string with line-breaks between them.\n\t\t.join( '\\n' );\n}\n\nfunction extractExpressions( content: string ): TranslationCallExpression[] {\n\tconst expressions: TranslationCallExpression[] = [];\n\n\t[ ...TRANSLATIONS_REGEXPS, ...COMMENTS_REGEXPS ].forEach( ( regexp ) => {\n\t\t[ ...content.matchAll( regexp ) ].forEach( ( res ) => {\n\t\t\texpressions.push( {\n\t\t\t\ttype: COMMENTS_REGEXPS.includes( regexp ) ? 'comment' : 'call-expression',\n\t\t\t\tindex: res.index || 0,\n\t\t\t\tvalue: res[ 0 ],\n\t\t\t} );\n\t\t} );\n\t} );\n\n\t// Sort by the index it was found in the file based on the regexp (and not by the order it was added to the array).\n\treturn expressions.sort( ( a, b ) => a.index - b.index );\n}\n"],"mappings":"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","names":["fs","path"]}
1
+ {"version":3,"sources":["../src/plugin.ts","../src/utils.ts"],"sourcesContent":["import * as path from 'path';\nimport * as fs from 'fs';\nimport { Compilation, Compiler } from 'webpack';\nimport { EntrySettings } from './types';\nimport { createStringsFilePath, generateStringsFileContent, getFilesContents, getFilesPaths } from './utils';\n\ntype Options = {\n\tpattern: ( entryPath: string, entryId: string ) => string;\n};\n\nexport default class ExtractI18nWordpressExpressionsWebpackPlugin {\n\toptions: Options;\n\n\tconstructor( options: Options ) {\n\t\tthis.options = options;\n\t}\n\n\tapply( compiler: Compiler ) {\n\t\tcompiler.hooks.afterEmit.tapPromise( this.constructor.name, async ( compilation ) => {\n\t\t\tconst entries = this.getEntries( compilation );\n\n\t\t\tawait Promise.all(\n\t\t\t\tentries.map( async ( entry ) => {\n\t\t\t\t\tconst fileContents = await getFilesContents( await getFilesPaths( entry.pattern ) );\n\n\t\t\t\t\tconst entryContent = generateStringsFileContent( fileContents );\n\n\t\t\t\t\t// Writing manually instead of using `chunk.files.add()` in order to avoid passing\n\t\t\t\t\t// the file through the loaders (transpilers, minifiers, etc.).\n\t\t\t\t\tawait fs.promises.writeFile( entry.path, entryContent );\n\t\t\t\t} )\n\t\t\t);\n\t\t} );\n\t}\n\n\tgetEntries( compilation: Compilation ) {\n\t\treturn [ ...compilation.entrypoints ]\n\t\t\t.map( ( [ id, entrypoint ] ) => {\n\t\t\t\tconst chunk = entrypoint.chunks.find( ( { name } ) => name === id );\n\n\t\t\t\tif ( ! chunk ) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\tconst chunkJSFile = [ ...chunk.files ].find( ( f ) => /\\.(js|ts)$/i.test( f ) );\n\n\t\t\t\tif ( ! chunkJSFile ) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\tconst { path: basePath } = compilation.options.output;\n\n\t\t\t\tif ( ! basePath ) {\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\n\t\t\t\tconst filePath = createStringsFilePath( compilation.getPath( '[file]', { filename: chunkJSFile } ) );\n\n\t\t\t\treturn {\n\t\t\t\t\tid,\n\t\t\t\t\tchunk,\n\t\t\t\t\tpath: path.join( basePath, filePath ),\n\t\t\t\t\tpattern: this.options.pattern( path.resolve( process.cwd(), entrypoint.origins[ 0 ].request ), id ),\n\t\t\t\t};\n\t\t\t} )\n\t\t\t.filter( Boolean ) as EntrySettings[];\n\t}\n}\n","import { TranslationCallExpression } from './types';\nimport { glob } from 'glob';\nimport * as fs from 'fs';\n\nconst COMMENTS_REGEXPS = [\n\t// Matches translators comment block: `/* translators: %s */`.\n\t/\\/\\*[\\t ]*translators:.*\\*\\//gm,\n\t// Matches translators inline comment: `// translators: %s`.\n\t/(\\/\\/)[\\t ]*translators:[^\\r\\n]*/gm,\n] as const;\n\nconst TRANSLATIONS_REGEXPS = [\n\t// Matches translation functions: `__('Hello', 'elementor')`, `_n('Me', 'Us', 2, 'elementor-pro')`.\n\t/\\b_(?:_|n|nx|x)\\(.*?,\\s*(?<c>['\"`])[\\w-]+\\k<c>\\s*?\\)/gs,\n] as const;\n\nexport function createStringsFilePath( path: string, suffix = '.strings.js' ) {\n\treturn path.replace( /(\\.min)?\\.js$/i, suffix );\n}\n\nexport function getFilesPaths( pattern: string ) {\n\treturn glob( pattern, {\n\t\tignore: {\n\t\t\tignored: ( p ) => ! /\\.(js|ts|jsx|tsx)$/.test( p.name ),\n\t\t\tchildrenIgnored: ( p ) => p.isNamed( '__tests__' ) || p.isNamed( '__mocks__' ),\n\t\t},\n\n\t\t/**\n\t\t * Fix for Windows paths escaping.\n\t\t * Note: This means we don't support paths with special character (like `*`,`?`, etc.)\n\t\t * and only allow patterns that are constructed using `path.join()` or `path.resolve()`.\n\t\t *\n\t\t * @see https://github.com/isaacs/node-glob#options\n\t\t * @see https://github.com/isaacs/node-glob#windows\n\t\t * @see https://github.com/isaacs/node-glob/issues/212#issuecomment-1449062925\n\t\t */\n\t\twindowsPathsNoEscape: true,\n\t} );\n}\n\nexport function getFilesContents( paths: string[] ) {\n\treturn Promise.all( paths.map( ( filePath ) => fs.promises.readFile( filePath, 'utf-8' ) ) );\n}\n\nexport function generateStringsFileContent( contents: string[] ) {\n\treturn (\n\t\tcontents\n\t\t\t.map( ( content ) => extractExpressions( content ) )\n\t\t\t.flat()\n\t\t\t// Add a semicolon when needed.\n\t\t\t.map( ( expr ) => `${ expr.value }${ expr.type === 'comment' ? '' : ';' }` )\n\t\t\t// Join all the expressions to a single string with line-breaks between them.\n\t\t\t.join( '\\n' )\n\t);\n}\n\nfunction extractExpressions( content: string ): TranslationCallExpression[] {\n\tconst expressions: TranslationCallExpression[] = [];\n\n\t[ ...TRANSLATIONS_REGEXPS, ...COMMENTS_REGEXPS ].forEach( ( regexp ) => {\n\t\t[ ...content.matchAll( regexp ) ].forEach( ( res ) => {\n\t\t\texpressions.push( {\n\t\t\t\ttype: COMMENTS_REGEXPS.includes( regexp ) ? 'comment' : 'call-expression',\n\t\t\t\tindex: res.index || 0,\n\t\t\t\tvalue: res[ 0 ],\n\t\t\t} );\n\t\t} );\n\t} );\n\n\t// Sort by the index it was found in the file based on the regexp (and not by the order it was added to the array).\n\treturn expressions.sort( ( a, b ) => a.index - b.index );\n}\n"],"mappings":"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","names":["fs","path"]}
package/package.json CHANGED
@@ -1,41 +1,48 @@
1
1
  {
2
- "name": "@elementor/extract-i18n-wordpress-expressions-webpack-plugin",
3
- "version": "0.3.1",
4
- "private": false,
5
- "author": "Elementor Team",
6
- "homepage": "https://elementor.com/",
7
- "license": "GPL-3.0-or-later",
8
- "main": "dist/index.js",
9
- "module": "dist/index.mjs",
10
- "types": "dist/index.d.ts",
11
- "exports": {
12
- ".": {
13
- "import": "./dist/index.mjs",
14
- "require": "./dist/index.js",
15
- "types": "./dist/index.d.ts"
16
- },
17
- "./package.json": "./package.json"
18
- },
19
- "repository": {
20
- "type": "git",
21
- "url": "https://github.com/elementor/elementor-packages.git",
22
- "directory": "packages/tools/extract-i18n-wordpress-expressions-webpack-plugin"
23
- },
24
- "bugs": {
25
- "url": "https://github.com/elementor/elementor-packages/issues"
26
- },
27
- "publishConfig": {
28
- "access": "public"
29
- },
30
- "scripts": {
31
- "build": "tsup --config=../../tsup.build.ts",
32
- "dev": "tsup --config=../../tsup.dev.ts --format=esm,cjs"
33
- },
34
- "peerDependencies": {
35
- "webpack": "5.x"
36
- },
37
- "dependencies": {
38
- "glob": "^10.3.10"
39
- },
40
- "gitHead": "020375ae889f6e0e237c34421cef7445b704b273"
2
+ "name": "@elementor/extract-i18n-wordpress-expressions-webpack-plugin",
3
+ "version": "0.3.3",
4
+ "private": false,
5
+ "author": "Elementor Team",
6
+ "homepage": "https://elementor.com/",
7
+ "license": "GPL-3.0-or-later",
8
+ "main": "dist/index.js",
9
+ "module": "dist/index.mjs",
10
+ "types": "dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "import": "./dist/index.mjs",
14
+ "require": "./dist/index.js",
15
+ "types": "./dist/index.d.ts"
16
+ },
17
+ "./package.json": "./package.json"
18
+ },
19
+ "repository": {
20
+ "type": "git",
21
+ "url": "git+https://github.com/elementor/elementor-packages.git",
22
+ "directory": "packages/tools/extract-i18n-wordpress-expressions-webpack-plugin"
23
+ },
24
+ "bugs": {
25
+ "url": "https://github.com/elementor/elementor-packages/issues"
26
+ },
27
+ "publishConfig": {
28
+ "access": "public"
29
+ },
30
+ "files": [
31
+ "README.md",
32
+ "CHANGELOG.md",
33
+ "/dist",
34
+ "/src",
35
+ "!**/__tests__"
36
+ ],
37
+ "scripts": {
38
+ "build": "tsup --config=../../tsup.build.ts",
39
+ "dev": "tsup --config=../../tsup.dev.ts --format=esm,cjs"
40
+ },
41
+ "peerDependencies": {
42
+ "webpack": "5.x"
43
+ },
44
+ "dependencies": {
45
+ "glob": "^10.3.10"
46
+ },
47
+ "gitHead": "f4ca33da0842a29d83736d0a173633085edddaee"
41
48
  }
package/src/plugin.ts CHANGED
@@ -2,16 +2,11 @@ import * as path from 'path';
2
2
  import * as fs from 'fs';
3
3
  import { Compilation, Compiler } from 'webpack';
4
4
  import { EntrySettings } from './types';
5
- import {
6
- createStringsFilePath,
7
- generateStringsFileContent,
8
- getFilesContents,
9
- getFilesPaths,
10
- } from './utils';
5
+ import { createStringsFilePath, generateStringsFileContent, getFilesContents, getFilesPaths } from './utils';
11
6
 
12
7
  type Options = {
13
8
  pattern: ( entryPath: string, entryId: string ) => string;
14
- }
9
+ };
15
10
 
16
11
  export default class ExtractI18nWordpressExpressionsWebpackPlugin {
17
12
  options: Options;
@@ -26,9 +21,7 @@ export default class ExtractI18nWordpressExpressionsWebpackPlugin {
26
21
 
27
22
  await Promise.all(
28
23
  entries.map( async ( entry ) => {
29
- const fileContents = await getFilesContents(
30
- await getFilesPaths( entry.pattern )
31
- );
24
+ const fileContents = await getFilesContents( await getFilesPaths( entry.pattern ) );
32
25
 
33
26
  const entryContent = generateStringsFileContent( fileContents );
34
27
 
@@ -67,10 +60,7 @@ export default class ExtractI18nWordpressExpressionsWebpackPlugin {
67
60
  id,
68
61
  chunk,
69
62
  path: path.join( basePath, filePath ),
70
- pattern: this.options.pattern(
71
- path.resolve( process.cwd(), entrypoint.origins[ 0 ].request ),
72
- id
73
- ),
63
+ pattern: this.options.pattern( path.resolve( process.cwd(), entrypoint.origins[ 0 ].request ), id ),
74
64
  };
75
65
  } )
76
66
  .filter( Boolean ) as EntrySettings[];
package/src/types.ts CHANGED
@@ -1,14 +1,14 @@
1
1
  import { Chunk } from 'webpack';
2
2
 
3
3
  export type EntrySettings = {
4
- id: string,
5
- chunk: Chunk,
6
- path: string,
7
- pattern: string,
8
- }
4
+ id: string;
5
+ chunk: Chunk;
6
+ path: string;
7
+ pattern: string;
8
+ };
9
9
 
10
10
  export type TranslationCallExpression = {
11
- type: 'comment' | 'call-expression',
12
- index: number,
13
- value: string,
11
+ type: 'comment' | 'call-expression';
12
+ index: number;
13
+ value: string;
14
14
  };
package/src/utils.ts CHANGED
@@ -11,7 +11,7 @@ const COMMENTS_REGEXPS = [
11
11
 
12
12
  const TRANSLATIONS_REGEXPS = [
13
13
  // Matches translation functions: `__('Hello', 'elementor')`, `_n('Me', 'Us', 2, 'elementor-pro')`.
14
- /\b_(?:_|n|nx|x)\(.*?,\s*(?<c>['"`])[\w-]+\k<c>\s*?\)/sg,
14
+ /\b_(?:_|n|nx|x)\(.*?,\s*(?<c>['"`])[\w-]+\k<c>\s*?\)/gs,
15
15
  ] as const;
16
16
 
17
17
  export function createStringsFilePath( path: string, suffix = '.strings.js' ) {
@@ -21,7 +21,7 @@ export function createStringsFilePath( path: string, suffix = '.strings.js' ) {
21
21
  export function getFilesPaths( pattern: string ) {
22
22
  return glob( pattern, {
23
23
  ignore: {
24
- ignored: ( p ) => ! ( /\.(js|ts|jsx|tsx)$/.test( p.name ) ),
24
+ ignored: ( p ) => ! /\.(js|ts|jsx|tsx)$/.test( p.name ),
25
25
  childrenIgnored: ( p ) => p.isNamed( '__tests__' ) || p.isNamed( '__mocks__' ),
26
26
  },
27
27
 
@@ -43,13 +43,15 @@ export function getFilesContents( paths: string[] ) {
43
43
  }
44
44
 
45
45
  export function generateStringsFileContent( contents: string[] ) {
46
- return contents
47
- .map( ( content, ) => extractExpressions( content ) )
48
- .flat()
49
- // Add a semicolon when needed.
50
- .map( ( expr ) => `${ expr.value }${ expr.type === 'comment' ? '' : ';' }` )
51
- // Join all the expressions to a single string with line-breaks between them.
52
- .join( '\n' );
46
+ return (
47
+ contents
48
+ .map( ( content ) => extractExpressions( content ) )
49
+ .flat()
50
+ // Add a semicolon when needed.
51
+ .map( ( expr ) => `${ expr.value }${ expr.type === 'comment' ? '' : ';' }` )
52
+ // Join all the expressions to a single string with line-breaks between them.
53
+ .join( '\n' )
54
+ );
53
55
  }
54
56
 
55
57
  function extractExpressions( content: string ): TranslationCallExpression[] {
@@ -1,23 +0,0 @@
1
- // Jest Snapshot v1, https://goo.gl/fbAQLP
2
-
3
- exports[`@elementor/extract-i18n-wordpress-expressions-webpack-plugin should extract translations from scripts 1`] = `
4
- "__(
5
- 'Some long text with multiple lines in the function call',
6
- 'elementor'
7
- );
8
- __( "Unique domain", "some-plugin-slug" );
9
- // translators: %1$s - special placeholder.
10
- __('special placeholder %1$s','elementor' );
11
- // translators: %s - regular comment.
12
- __( 'regular comment %s','elementor');
13
- /* translators: %s - comment block. */
14
- __('comment block %s', 'elementor');
15
- __( 'inside console log', 'elementor' );
16
- _n( 'basic with', 'plural', 2, 'elementor' );
17
- _nx( 'another with' , 'plural' , 2 , 'elementor' );
18
- _x( 'context', 'elementor' );
19
- __('hook','elementor');
20
- __( "Component", 'elementor' );"
21
- `;
22
-
23
- exports[`@elementor/extract-i18n-wordpress-expressions-webpack-plugin should extract translations from scripts 2`] = `"__( 'from app 2', 'elementor' );"`;
@@ -1,130 +0,0 @@
1
- /**
2
- * @jest-environment node
3
- */
4
-
5
- import * as fs from 'fs';
6
- import * as path from 'path';
7
- import { webpack } from 'webpack';
8
- import { ExtractI18nWordpressExpressionsWebpackPlugin } from '../index';
9
- import { vol } from 'memfs';
10
-
11
- jest.mock( 'fs', () => jest.requireActual( 'memfs' ) );
12
-
13
- describe( '@elementor/extract-i18n-wordpress-expressions-webpack-plugin', () => {
14
- beforeEach( () => {
15
- // Entry file.
16
- fs.mkdirSync( path.resolve( '/app/dist' ), { recursive: true } );
17
- fs.writeFileSync( path.resolve( '/app/dist/index.js' ), '' );
18
-
19
- fs.mkdirSync( path.resolve( '/app2/dist' ), { recursive: true } );
20
- fs.writeFileSync( path.resolve( '/app2/dist/index.js' ), '' );
21
-
22
- // Should be in output.
23
- fs.mkdirSync( path.resolve( '/app/src' ), { recursive: true } );
24
- fs.mkdirSync( path.resolve( '/app/src/components' ), { recursive: true } );
25
- fs.mkdirSync( path.resolve( '/app/src/hooks' ), { recursive: true } );
26
-
27
- fs.writeFileSync( path.resolve( '/app/src/components/component.js' ), `
28
- export default function Component() {
29
- return __( "Component", 'elementor' );
30
- }
31
- ` );
32
-
33
- fs.writeFileSync( path.resolve( '/app/src/hooks/hook.ts' ), `
34
- export default function useHook() {
35
- return __('hook','elementor');
36
- }
37
- ` );
38
-
39
- fs.writeFileSync( path.resolve( '/app/src/index.js' ), `
40
- export default function Index() {
41
- __(
42
- 'Some long text with multiple lines in the function call',
43
- 'elementor'
44
- );
45
-
46
- __( "Unique domain", "some-plugin-slug" );
47
-
48
- // translators: %1$s - special placeholder.
49
- const withSpecialPlaceHolder = __('special placeholder %1$s','elementor' );
50
-
51
- // translators: %s - regular comment.
52
- const withComment = __( 'regular comment %s','elementor');
53
-
54
- /* translators: %s - comment block. */
55
- const withCommentBlock = __('comment block %s', 'elementor');
56
-
57
- console.log(__( 'inside console log', 'elementor' ))
58
-
59
- return [
60
- _n( 'basic with', 'plural', 2, 'elementor' ),
61
- _nx( 'another with' , 'plural' , 2 , 'elementor' ),
62
- _x( 'context', 'elementor' ),
63
- invalid__( 'invalid', 'elementor' ),
64
- ];
65
- }
66
- ` );
67
-
68
- fs.mkdirSync( path.resolve( '/app2/src' ), { recursive: true } );
69
- fs.writeFileSync( path.resolve( '/app2/src/index.js' ), `
70
- export const test = __( 'from app 2', 'elementor' );
71
- ` );
72
-
73
- // Should not be in output.
74
- const ignoredContent = `
75
- export default function ShouldIgnoreComponent() {
76
- return __('should ignore','elementor');
77
- }
78
- `;
79
-
80
- fs.mkdirSync( path.resolve( '/app/fake-src' ), { recursive: true } );
81
- fs.writeFileSync( path.resolve( '/app/fake-src/index.js' ), ignoredContent );
82
-
83
- fs.mkdirSync( path.resolve( '/app/src/__tests__' ), { recursive: true } );
84
- fs.writeFileSync( path.resolve( '/app/src/__tests__/mock.test.js' ), ignoredContent );
85
-
86
- fs.writeFileSync( path.resolve( '/app/src/not-a-js-file.txt' ), ignoredContent );
87
- } );
88
-
89
- afterEach( () => {
90
- vol.reset();
91
- } );
92
-
93
- it( 'should extract translations from scripts', ( done ) => {
94
- // Arrange.
95
- const compiler = webpack( {
96
- mode: 'development',
97
- entry: {
98
- app: path.resolve( '/app/dist/index.js' ),
99
- app2: path.resolve( '/app2/dist/index.js' ),
100
- },
101
- output: {
102
- filename: '[name]/[name].js',
103
- path: path.resolve( '/output' ),
104
- },
105
- plugins: [
106
- new ExtractI18nWordpressExpressionsWebpackPlugin( {
107
- pattern: ( entryPath ) => path.resolve( entryPath, '../../src/**/*.{ts,tsx,js,jsx}' ),
108
- } ),
109
- ],
110
- } );
111
-
112
- // Act.
113
- compiler.run( ( err, stats ) => {
114
- // Assert.
115
- expect( err ).toBe( null );
116
- expect( stats?.hasErrors() ).toBe( false );
117
- expect( stats?.hasWarnings() ).toBe( false );
118
-
119
- expect(
120
- fs.readFileSync( path.resolve( `/output/app/app.strings.js` ), { encoding: 'utf8' } )
121
- ).toMatchSnapshot();
122
-
123
- expect(
124
- fs.readFileSync( path.resolve( `/output/app2/app2.strings.js` ), { encoding: 'utf8' } )
125
- ).toMatchSnapshot();
126
-
127
- done();
128
- } );
129
- } );
130
- } );