44c355c7f0
* fix: do not attempt to cache i18n:extract * fix: i18n extraction * docs: improve comments
129 lines
3.8 KiB
TypeScript
129 lines
3.8 KiB
TypeScript
/* eslint-env node */
|
|
import { default as babelExtractor } from '@lingui/cli/api/extractors/babel'
|
|
import { createHash } from 'crypto'
|
|
import { mkdirSync, readFileSync, writeFileSync } from 'fs'
|
|
import { existsSync } from 'fs'
|
|
import * as path from 'path'
|
|
|
|
/** A custom caching extractor built on top of babelExtractor. */
|
|
const cachingExtractor: typeof babelExtractor = {
|
|
/** Delegates to babelExtractor.match. */
|
|
match(filename: string) {
|
|
return babelExtractor.match(filename)
|
|
},
|
|
/**
|
|
* Checks a cache before extraction, only delegating to babelExtractor.extract if the file has changed.
|
|
*
|
|
* The lingui extractor works by extracting JSON (the catalog) from `filename` to `buildDir/filename.json`.
|
|
* Caching works by man-in-the-middling this:
|
|
* - File freshness is computed as a hash of `filename` contents.
|
|
* - Before extracting, we check the cache to see if we already have a fresh catalog for the file.
|
|
* If we do, we copy it to `localeDir/filename.json`. Copying is significantly faster than extracting.
|
|
* - After extracting, we copy the catalog to the cache.
|
|
*/
|
|
extract(filename: string, localeDir: string, ...options: unknown[]) {
|
|
// This runs from node_modules/@lingui/conf, so we need to back out to the root.
|
|
const root = __dirname.split('/node_modules')[0]
|
|
|
|
// This logic mimics catalogFilename in @lingui/babel-plugin-extract-messages.
|
|
const buildDir = path.join(localeDir, '_build')
|
|
const localePath = path.join(buildDir, filename + '.json')
|
|
|
|
const filePath = path.join(root, filename)
|
|
const fileHash = createHash('sha256').update(readFileSync(filePath)).digest('hex')
|
|
|
|
const cacheRoot = path.join(root, 'node_modules/.cache/lingui')
|
|
const cachePath = path.join(cacheRoot, filename + '.json')
|
|
|
|
// If we have a matching cached copy of the catalog, we can copy it to localePath and return early.
|
|
if (existsSync(cachePath)) {
|
|
const { hash, catalog } = JSON.parse(readFileSync(cachePath, 'utf8'))
|
|
if (hash === fileHash) {
|
|
if (catalog) {
|
|
mkdirSync(path.dirname(localePath), { recursive: true })
|
|
writeFileSync(localePath, JSON.stringify(catalog, null, 2))
|
|
}
|
|
return
|
|
}
|
|
}
|
|
|
|
babelExtractor.extract(filename, localeDir, ...options)
|
|
|
|
// Cache the extracted catalog.
|
|
mkdirSync(path.dirname(cachePath), { recursive: true })
|
|
if (existsSync(localePath)) {
|
|
const catalog = JSON.parse(readFileSync(localePath, 'utf8'))
|
|
writeFileSync(cachePath, JSON.stringify({ hash: fileHash, catalog }))
|
|
} else {
|
|
writeFileSync(cachePath, JSON.stringify({ hash: fileHash }))
|
|
}
|
|
},
|
|
}
|
|
|
|
const linguiConfig = {
|
|
catalogs: [
|
|
{
|
|
path: '<rootDir>/src/locales/{locale}',
|
|
include: ['<rootDir>/src/**/*.ts', '<rootDir>/src/**/*.tsx'],
|
|
exclude: [
|
|
'<rootDir>/src/**/*.d.ts',
|
|
'<rootDir>/src/**/*.test.*',
|
|
'<rootDir>/src/types/v3/**',
|
|
'<rootDir>/src/abis/types/**',
|
|
'<rootDir>/src/graphql/**/__generated__/**',
|
|
],
|
|
},
|
|
],
|
|
compileNamespace: 'cjs',
|
|
fallbackLocales: {
|
|
default: 'en-US',
|
|
},
|
|
format: 'po',
|
|
formatOptions: {
|
|
lineNumbers: false,
|
|
},
|
|
locales: [
|
|
'af-ZA',
|
|
'ar-SA',
|
|
'ca-ES',
|
|
'cs-CZ',
|
|
'da-DK',
|
|
'de-DE',
|
|
'el-GR',
|
|
'en-US',
|
|
'es-ES',
|
|
'fi-FI',
|
|
'fr-FR',
|
|
'he-IL',
|
|
'hu-HU',
|
|
'id-ID',
|
|
'it-IT',
|
|
'ja-JP',
|
|
'ko-KR',
|
|
'nl-NL',
|
|
'no-NO',
|
|
'pl-PL',
|
|
'pt-BR',
|
|
'pt-PT',
|
|
'ro-RO',
|
|
'ru-RU',
|
|
'sr-SP',
|
|
'sv-SE',
|
|
'sw-TZ',
|
|
'tr-TR',
|
|
'uk-UA',
|
|
'vi-VN',
|
|
'zh-CN',
|
|
'zh-TW',
|
|
'pseudo',
|
|
],
|
|
orderBy: 'messageId',
|
|
rootDir: '.',
|
|
runtimeConfigModule: ['@lingui/core', 'i18n'],
|
|
sourceLocale: 'en-US',
|
|
pseudoLocale: 'pseudo',
|
|
extractors: [cachingExtractor],
|
|
}
|
|
|
|
export default linguiConfig
|