diff --git a/package.json b/package.json index edb451308..c95b61f47 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,6 @@ "@types/jest": "^29.4.0", "@types/mock-fs": "^4.13.1", "@types/node": "20.14.8", - "@types/ramda": "^0.27.23", "babel-jest": "^29.7.0", "chalk": "^4.1.0", "cross-env": "^7.0.2", diff --git a/packages/cli/package.json b/packages/cli/package.json index 16824b3a1..3bf5142d1 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -80,7 +80,6 @@ "pkg-up": "^3.1.0", "pofile": "^1.1.4", "pseudolocale": "^2.0.0", - "ramda": "^0.27.1", "source-map": "^0.8.0-beta.0" }, "devDependencies": { diff --git a/packages/cli/src/api/catalog.test.ts b/packages/cli/src/api/catalog.test.ts index fef43270c..e8b2152fe 100644 --- a/packages/cli/src/api/catalog.test.ts +++ b/packages/cli/src/api/catalog.test.ts @@ -528,7 +528,7 @@ describe("order", () => { }), } - const orderedCatalogs = order("messageId")(catalog) + const orderedCatalogs = order("messageId", catalog) // Test that the message content is the same as before expect(orderedCatalogs).toMatchSnapshot() @@ -560,7 +560,7 @@ describe("order", () => { }), } - const orderedCatalogs = order("origin")(catalog) + const orderedCatalogs = order("origin", catalog) // Test that the message content is the same as before expect(orderedCatalogs).toMatchSnapshot() @@ -596,7 +596,7 @@ describe("order", () => { }), } - const orderedCatalogs = order("message")(catalog) + const orderedCatalogs = order("message", catalog) // Jest snapshot order the keys automatically, so test that the key order explicitly expect(Object.keys(orderedCatalogs)).toMatchInlineSnapshot(` diff --git a/packages/cli/src/api/catalog.ts b/packages/cli/src/api/catalog.ts index 7b0e02b6f..2703c67a3 100644 --- a/packages/cli/src/api/catalog.ts +++ b/packages/cli/src/api/catalog.ts @@ -1,6 +1,5 @@ import fs from "fs" import path from "path" -import * as R from "ramda" import { globSync } from "glob" import normalize from "normalize-path" @@ -23,12 +22,7 @@ import { replacePlaceholders, writeFile, } from "./utils" -import { - AllCatalogsType, - CatalogType, - ExtractedCatalogType, - ExtractedMessageType, -} from "./types" +import { AllCatalogsType, CatalogType, ExtractedCatalogType } from "./types" const LOCALE = "{locale}" const LOCALE_SUFFIX_RE = /\{locale\}.*$/ @@ -95,16 +89,17 @@ export class Catalog { }) // Map over all locales and post-process each catalog - const cleanAndSort = R.map( - R.pipe( - // Clean obsolete messages - (options.clean ? cleanObsolete : R.identity) as any, - // Sort messages - order(options.orderBy) - ) - ) as unknown as (catalog: AllCatalogsType) => AllCatalogsType + const sortedCatalogs = Object.fromEntries( + Object.entries(catalogs).map(([locale, catalog]) => { + if (options.clean) { + catalog = cleanObsolete(catalog) + } - const sortedCatalogs = cleanAndSort(catalogs) + catalog = order(options.orderBy, catalog) + + return [locale, catalog] + }) + ) as AllCatalogsType const locales = options.locale ? options.locale : this.locales await Promise.all( @@ -119,7 +114,7 @@ export class Catalog { ): Promise { const catalog = await this.collect({ files: options.files }) if (!catalog) return false - const sorted = order(options.orderBy)(catalog as CatalogType) + const sorted = order(options.orderBy, catalog as CatalogType) await this.writeTemplate(sorted) return sorted @@ -169,14 +164,17 @@ export class Catalog { nextCatalog: ExtractedCatalogType, options: MergeOptions ) { - return R.mapObjIndexed((prevCatalog, locale) => { - return mergeCatalog( - prevCatalog, - nextCatalog, - this.config.sourceLocale === locale, - options - ) - }, prevCatalogs) + return Object.fromEntries( + Object.entries(prevCatalogs).map(([locale, prevCatalog]) => [ + locale, + mergeCatalog( + prevCatalog, + nextCatalog, + this.config.sourceLocale === locale, + options + ), + ]) + ) } async getTranslations(locale: string, options: GetTranslationsOptions) { @@ -287,20 +285,22 @@ function getTemplatePath(ext: string, path: string) { return path.replace(LOCALE_SUFFIX_RE, "messages" + ext) } -export const cleanObsolete = R.filter( - (message: ExtractedMessageType) => !message.obsolete -) +export function cleanObsolete(messages: T): T { + return Object.fromEntries( + Object.entries(messages).filter(([, message]) => !message.obsolete) + ) as T +} export function order( - by: OrderBy -): (catalog: T) => T { + by: OrderBy, + catalog: T +): T { return { messageId: orderByMessageId, message: orderByMessage, origin: orderByOrigin, - }[by] + }[by](catalog) } - /** * Object keys are in the same order as they were created * https://stackoverflow.com/a/31102605/1535540 diff --git a/packages/cli/src/api/catalog/mergeCatalog.ts b/packages/cli/src/api/catalog/mergeCatalog.ts index 73b1a1f81..c00881aa1 100644 --- a/packages/cli/src/api/catalog/mergeCatalog.ts +++ b/packages/cli/src/api/catalog/mergeCatalog.ts @@ -1,6 +1,5 @@ -import * as R from "ramda" import type { MergeOptions } from "../catalog" -import { CatalogType, ExtractedCatalogType, MessageType } from "../types" +import { CatalogType, ExtractedCatalogType } from "../types" export function mergeCatalog( prevCatalog: CatalogType, @@ -9,49 +8,52 @@ export function mergeCatalog( options: MergeOptions ): CatalogType { const nextKeys = Object.keys(nextCatalog) + const prevKeys = Object.keys(prevCatalog || {}) - const prevKeys = R.keys(prevCatalog).map(String) - - const newKeys = R.difference(nextKeys, prevKeys) - const mergeKeys = R.intersection(nextKeys, prevKeys) - const obsoleteKeys = R.difference(prevKeys, nextKeys) + const newKeys = nextKeys.filter((key) => !prevKeys.includes(key)) + const mergeKeys = nextKeys.filter((key) => prevKeys.includes(key)) + const obsoleteKeys = prevKeys.filter((key) => !nextKeys.includes(key)) // Initialize new catalog with new keys - const newMessages = R.mapObjIndexed( - (message: MessageType, key) => ({ - translation: forSourceLocale ? message.message || key : "", - ...message, - }), - R.pick(newKeys, nextCatalog) + const newMessages: CatalogType = Object.fromEntries( + newKeys.map((key) => [ + key, + { + translation: forSourceLocale ? nextCatalog[key].message || key : "", + ...nextCatalog[key], + }, + ]) ) // Merge translations from previous catalog - const mergedMessages = mergeKeys.map((key) => { - const updateFromDefaults = - forSourceLocale && - (prevCatalog[key].translation === prevCatalog[key].message || - options.overwrite) - - const translation = updateFromDefaults - ? nextCatalog[key].message || key - : prevCatalog[key].translation - - return { - [key]: { - translation, - ...R.omit(["obsolete, translation"], nextCatalog[key]), - }, - } - }) + const mergedMessages = Object.fromEntries( + mergeKeys.map((key) => { + const updateFromDefaults = + forSourceLocale && + (prevCatalog[key].translation === prevCatalog[key].message || + options.overwrite) + + const translation = updateFromDefaults + ? nextCatalog[key].message || key + : prevCatalog[key].translation + + const { obsolete, ...rest } = nextCatalog[key] + + return [key, { ...rest, translation }] + }) + ) // Mark all remaining translations as obsolete // Only if *options.files* is not provided - const obsoleteMessages = obsoleteKeys.map((key) => ({ - [key]: { - ...prevCatalog[key], - ...(!options.files && { obsolete: true }), - }, - })) - - return R.mergeAll([newMessages, ...mergedMessages, ...obsoleteMessages]) + const obsoleteMessages = Object.fromEntries( + obsoleteKeys.map((key) => [ + key, + { + ...prevCatalog[key], + ...(options.files ? {} : { obsolete: true }), + }, + ]) + ) + + return { ...newMessages, ...mergedMessages, ...obsoleteMessages } } diff --git a/packages/cli/src/api/pseudoLocalize.ts b/packages/cli/src/api/pseudoLocalize.ts index 51f79f802..891dd197b 100644 --- a/packages/cli/src/api/pseudoLocalize.ts +++ b/packages/cli/src/api/pseudoLocalize.ts @@ -1,4 +1,3 @@ -import R from "ramda" import pseudolocale from "pseudolocale" const delimiter = "%&&&%" @@ -45,18 +44,14 @@ function addDelimitersVariables(message: string) { }) } -const addDelimiters = R.compose( - addDelimitersVariables, - addDelimitersMacro, - addDelimitersHTMLTags -) - function removeDelimiters(message: string) { return message.replace(new RegExp(delimiter, "g"), "") } export default function (message: string) { - message = addDelimiters(message) + message = addDelimitersHTMLTags(message) + message = addDelimitersMacro(message) + message = addDelimitersVariables(message) message = pseudolocale(message, { delimiter, prepend: "", diff --git a/packages/cli/src/extract-experimental/writeCatalogs.ts b/packages/cli/src/extract-experimental/writeCatalogs.ts index c5cecf620..4648aa12b 100644 --- a/packages/cli/src/extract-experimental/writeCatalogs.ts +++ b/packages/cli/src/extract-experimental/writeCatalogs.ts @@ -30,7 +30,7 @@ function cleanAndSort(catalog: CatalogType, clean: boolean, orderBy: OrderBy) { catalog = cleanObsolete(catalog) } - return order(orderBy)(catalog) as CatalogType + return order(orderBy, catalog) as CatalogType } export async function writeCatalogs( diff --git a/packages/format-json/package.json b/packages/format-json/package.json index f274885ab..4c0f599a5 100644 --- a/packages/format-json/package.json +++ b/packages/format-json/package.json @@ -39,8 +39,7 @@ "dist/" ], "dependencies": { - "@lingui/conf": "5.1.2", - "ramda": "^0.28.0" + "@lingui/conf": "5.1.2" }, "devDependencies": { "tsd": "^0.28.0", diff --git a/packages/format-json/src/json.ts b/packages/format-json/src/json.ts index b9684c45b..fe138ff41 100644 --- a/packages/format-json/src/json.ts +++ b/packages/format-json/src/json.ts @@ -1,10 +1,7 @@ -import * as R from "ramda" - import { CatalogFormatter, CatalogType, ExtractedMessageType, - MessageType, } from "@lingui/conf" export type JsonFormatterOptions = { @@ -43,27 +40,50 @@ type NoOriginsCatalogType = { type MinimalCatalogType = Record -const serializeMinimal = R.map( - (message: MessageType) => message.translation || "" -) as unknown as (catalog: CatalogType) => MinimalCatalogType +const serializeMinimal = (catalog: CatalogType): MinimalCatalogType => { + const result: MinimalCatalogType = {} + for (const key in catalog) { + result[key] = catalog[key].translation || "" + } + return result +} -const deserializeMinimal = R.map((translation: string) => ({ - translation, - obsolete: false, - message: null, - origin: [], -})) as unknown as (minimalCatalog: MinimalCatalogType) => CatalogType +const deserializeMinimal = ( + minimalCatalog: MinimalCatalogType +): CatalogType => { + const result: CatalogType = {} + for (const key in minimalCatalog) { + result[key] = { + translation: minimalCatalog[key], + obsolete: false, + message: null, + origin: [], + } + } + return result +} -const removeOrigins = R.map(({ origin, ...message }) => message) as unknown as ( - catalog: CatalogType -) => NoOriginsCatalogType +const removeOrigins = (catalog: CatalogType): NoOriginsCatalogType => { + const result: NoOriginsCatalogType = {} + for (const key in catalog) { + const { origin, ...message } = catalog[key] + result[key] = message + } + return result +} -const removeLineNumbers = R.map((message: ExtractedMessageType) => { - if (message.origin) { - message.origin = message.origin.map(([file]) => [file]) +const removeLineNumbers = ( + catalog: ExtractedMessageType +): NoOriginsCatalogType => { + const result: NoOriginsCatalogType = {} + for (const key in catalog) { + result[key] = { + ...catalog[key], + origin: catalog[key].origin?.map(([file]) => [file]), + } } - return message -}) as unknown as (catalog: ExtractedMessageType) => NoOriginsCatalogType + return result +} export function formatter( options: JsonFormatterOptions = {} diff --git a/packages/remote-loader/package.json b/packages/remote-loader/package.json index 169a8a457..d733fb4f8 100644 --- a/packages/remote-loader/package.json +++ b/packages/remote-loader/package.json @@ -50,8 +50,7 @@ ], "dependencies": { "@lingui/core": "4.0.0", - "@lingui/message-utils": "4.0.0", - "ramda": "^0.27.1" + "@lingui/message-utils": "4.0.0" }, "devDependencies": { "unbuild": "2.0.0" diff --git a/packages/remote-loader/src/index.ts b/packages/remote-loader/src/index.ts index eca784c32..221c02a0e 100644 --- a/packages/remote-loader/src/index.ts +++ b/packages/remote-loader/src/index.ts @@ -1,4 +1,3 @@ -import * as R from "ramda" import { createBrowserCompiledCatalog } from "./browserCompiler" import PARSERS from "./minimalParser" @@ -8,7 +7,7 @@ type RemoteLoaderOpts = { messages: string | Record | T } -function remoteLoader({ +export function remoteLoader({ format = "minimal", fallbackMessages, messages, @@ -35,19 +34,16 @@ function remoteLoader({ `) } - const mapTranslationsToInterporlatedString = R.mapObjIndexed((_, key) => { + const mapTranslationsToInterpolatedString = Object.fromEntries( // if there's fallback and translation is empty, return the fallback - if ( + Object.keys(parsedMessages).map((key) => [ + key, parsedMessages[key].translation === "" && parsedFallbackMessages?.[key]?.translation - ) { - return parsedFallbackMessages[key].translation - } - - return parsedMessages[key].translation - }, parsedMessages) + ? parsedFallbackMessages[key].translation + : parsedMessages[key].translation, + ]) + ) - return createBrowserCompiledCatalog(mapTranslationsToInterporlatedString) + return createBrowserCompiledCatalog(mapTranslationsToInterpolatedString) } - -export { remoteLoader } diff --git a/packages/remote-loader/src/minimalParser.ts b/packages/remote-loader/src/minimalParser.ts index 4be4683b7..5cf175e13 100644 --- a/packages/remote-loader/src/minimalParser.ts +++ b/packages/remote-loader/src/minimalParser.ts @@ -1,15 +1,19 @@ -import * as R from "ramda" - -const deserialize = R.map((translation: string) => ({ - translation, - obsolete: false, - message: null, - origin: [], -})) as unknown as (minimalCatalog: any) => any +const deserialize = (minimalCatalog: Record) => { + const result: Record = {} + for (const key in minimalCatalog) { + result[key] = { + translation: minimalCatalog[key], + obsolete: false, + message: null, + origin: [], + } + } + return result +} const PARSERS = { minimal: (content: Record | T) => { - return deserialize(content) + return deserialize(content as Record) }, }