From 6ae7998d5edbb52de750760bdc6005c0547d6825 Mon Sep 17 00:00:00 2001 From: cesarParra Date: Sun, 29 Jun 2025 08:17:45 -0400 Subject: [PATCH 1/6] Add translation system for customizable documentation labels - Introduce a translation system allowing users to override default English labels and terminology in generated documentation and changelogs --- examples/translation-example/README.md | 267 ++++++++++++++++++ .../translation-example/apexdocs.config.js | 130 +++++++++ src/core/changelog/generate-change-log.ts | 25 +- src/core/changelog/renderable-changelog.ts | 105 ++++--- .../changelog/templates/changelog-template.ts | 2 +- .../__tests__/interface-adapter.spec.ts | 6 + .../adapters/fields-and-properties.ts | 6 +- .../adapters/methods-and-constructors.ts | 17 +- .../markdown/adapters/renderable-bundle.ts | 9 +- .../adapters/renderable-to-page-data.ts | 24 +- .../markdown/adapters/type-to-renderable.ts | 157 ++++++---- src/core/markdown/generate-docs.ts | 5 +- src/core/markdown/templates/class-template.ts | 4 +- .../templates/custom-object-template.ts | 20 +- .../markdown/templates/type-doc-partial.ts | 10 +- src/core/shared/types.d.ts | 3 + .../__tests__/translation-utils.test.ts | 267 ++++++++++++++++++ src/core/translations/default-translations.ts | 252 +++++++++++++++++ src/core/translations/index.ts | 2 + src/core/translations/translation-utils.ts | 109 +++++++ src/index.ts | 3 + 21 files changed, 1286 insertions(+), 137 deletions(-) create mode 100644 examples/translation-example/README.md create mode 100644 examples/translation-example/apexdocs.config.js create mode 100644 src/core/translations/__tests__/translation-utils.test.ts create mode 100644 src/core/translations/default-translations.ts create mode 100644 src/core/translations/index.ts create mode 100644 src/core/translations/translation-utils.ts diff --git a/examples/translation-example/README.md b/examples/translation-example/README.md new file mode 100644 index 00000000..036049d7 --- /dev/null +++ b/examples/translation-example/README.md @@ -0,0 +1,267 @@ +# Sample Project With Provided Translations + +Demonstrates how to provide translations to ApexDocs to customize the language and terminology used in generated documentation. + +## Overview + +The translation feature allows you to: + +1. **Translate documentation to different languages** (Spanish, French, etc.) +2. **Use custom business terminology** (e.g., "Business Operations" instead of "Methods") +3. **Partially override specific terms** while keeping the rest in English +4. **Maintain consistency** across your organization's documentation standards + +## How It Works + +ApexDocs uses a translation system with: + +- **Default English translations** built into the system +- **User-provided overrides** that can be partial or complete +- **Deep merging** so you only need to specify what you want to change + +## Configuration + +Add a `translations` property to your ApexDocs configuration: + +```javascript +import { defineMarkdownConfig } from '@cparra/apexdocs'; + +export default defineMarkdownConfig({ + sourceDir: 'src', + targetDir: 'docs', + scope: ['public', 'global'], + translations: { + // Your custom translations here + markdown: { + sections: { + methods: 'Métodos', + properties: 'Propiedades', + fields: 'Campos', + }, + }, + }, +}); +``` + +## Translation Structure + +The translation object has two main sections: + +### Changelog Translations + +```javascript +{ + changelog: { + title: 'Changelog', + newClasses: { + heading: 'New Classes', + description: 'These classes are new.', + }, + newInterfaces: { + heading: 'New Interfaces', + description: 'These interfaces are new.', + }, + // ... more changelog sections + memberModifications: { + newMethod: 'New Method', + removedMethod: 'Removed Method', + // ... more modification types + }, + } +} +``` + +### Markdown Documentation Translations + +```javascript +{ + markdown: { + sections: { + methods: 'Methods', + properties: 'Properties', + fields: 'Fields', + constructors: 'Constructors', + values: 'Values', // for enums + classes: 'Classes', // for inner classes + enums: 'Enums', // for inner enums + interfaces: 'Interfaces', // for inner interfaces + namespace: 'Namespace', + records: 'Records', // for custom metadata + publishBehavior: 'Publish Behavior', + }, + details: { + type: 'Type', + signature: 'Signature', + group: 'Group', + author: 'Author', + date: 'Date', + see: 'See', + possibleValues: 'Possible values are', + parameters: 'Parameters', + throws: 'Throws', + returnType: 'Return Type', + apiName: 'API Name', + required: 'Required', + // ... more detail labels + }, + typeSuffixes: { + class: 'Class', + interface: 'Interface', + enum: 'Enum', + trigger: 'Trigger', + }, + triggerEvents: { + beforeInsert: 'Before Insert', + beforeUpdate: 'Before Update', + // ... more trigger events + }, + publishBehaviors: { + publishImmediately: 'Publish Immediately', + publishAfterCommit: 'Publish After Commit', + }, + inheritance: { + inheritance: 'Inheritance', + implements: 'Implements', + }, + } +} +``` + +## Examples + +### Complete Spanish Translation + +```javascript +const spanishTranslations = { + changelog: { + title: 'Registro de Cambios', + newClasses: { + heading: 'Nuevas Clases', + description: 'Estas clases son nuevas.', + }, + // ... more changelog translations + }, + markdown: { + sections: { + methods: 'Métodos', + properties: 'Propiedades', + fields: 'Campos', + constructors: 'Constructores', + }, + details: { + type: 'Tipo', + signature: 'Firma', + parameters: 'Parámetros', + }, + typeSuffixes: { + class: 'Clase', + interface: 'Interfaz', + enum: 'Enum', + }, + }, +}; +``` + +### Custom Business Terminology + +```javascript +const businessTerminology = { + markdown: { + sections: { + methods: 'Business Operations', + properties: 'Business Attributes', + fields: 'Data Elements', + constructors: 'Initializers', + }, + typeSuffixes: { + class: 'Service', + interface: 'Contract', + }, + }, +}; +``` + +### Partial Overrides + +```javascript +const partialTranslations = { + markdown: { + sections: { + methods: 'Functions', // Only change "Methods" to "Functions" + }, + }, +}; +``` + +## Usage with Different Generators + +### Markdown Generator + +```javascript +export default defineMarkdownConfig({ + sourceDir: 'src', + targetDir: 'docs', + scope: ['public', 'global'], + translations: yourTranslations, +}); +``` + +### Changelog Generator + +```javascript +export default defineChangelogConfig({ + previousVersionDir: 'previous', + currentVersionDir: 'current', + targetDir: 'changelog', + fileName: 'CHANGELOG', + scope: ['public', 'global'], + translations: yourTranslations, +}); +``` + +## Best Practices + +1. **Start Small**: Begin with partial translations for the most important terms +2. **Be Consistent**: Use the same terminology across your organization +3. **Test Thoroughly**: Generate documentation with your translations to verify the output +4. **Document Your Choices**: Keep track of your translation decisions for future reference +5. **Version Control**: Include your translation configurations in version control + +## TypeScript Support + +If you're using TypeScript, you can import the translation types for better autocomplete and type safety: + +```typescript +import { defineMarkdownConfig } from '@cparra/apexdocs'; +import type { UserTranslations } from '@cparra/apexdocs'; + +const translations: UserTranslations = { + markdown: { + sections: { + methods: 'Functions', + }, + }, +}; + +export default defineMarkdownConfig({ + sourceDir: 'src', + targetDir: 'docs', + scope: ['public', 'global'], + translations, +}); +``` + +## Validation + +The translation system includes basic validation to catch common mistakes: + +- Invalid top-level keys will generate warnings +- Missing translations fall back to English defaults +- Deep merging ensures you only need to specify what changes + +## Notes + +- Only the **markdown** and **changelog** generators support translations +- The **OpenAPI** generator does not use the translation system +- All translations are optional - anything not specified uses the English default +- The system uses deep merging, so partial translations work seamlessly diff --git a/examples/translation-example/apexdocs.config.js b/examples/translation-example/apexdocs.config.js new file mode 100644 index 00000000..99d90d8d --- /dev/null +++ b/examples/translation-example/apexdocs.config.js @@ -0,0 +1,130 @@ +import { defineMarkdownConfig, defineChangelogConfig } from '../../src/index.js'; + +// Example of using custom translations in different languages + +// Spanish translations example +const spanishTranslations = { + changelog: { + title: 'Registro de Cambios', + newClasses: { + heading: 'Nuevas Clases', + description: 'Estas clases son nuevas.', + }, + newInterfaces: { + heading: 'Nuevas Interfaces', + description: 'Estas interfaces son nuevas.', + }, + newEnums: { + heading: 'Nuevos Enums', + description: 'Estos enums son nuevos.', + }, + removedTypes: { + heading: 'Tipos Eliminados', + description: 'Estos tipos han sido eliminados.', + }, + memberModifications: { + newMethod: 'Nuevo Método', + removedMethod: 'Método Eliminado', + newProperty: 'Nueva Propiedad', + removedProperty: 'Propiedad Eliminada', + }, + }, + markdown: { + sections: { + methods: 'Métodos', + properties: 'Propiedades', + fields: 'Campos', + constructors: 'Constructores', + namespace: 'Espacio de Nombres', + }, + details: { + type: 'Tipo', + signature: 'Firma', + parameters: 'Parámetros', + returnType: 'Tipo de Retorno', + throws: 'Lanza', + }, + typeSuffixes: { + class: 'Clase', + interface: 'Interfaz', + enum: 'Enum', + trigger: 'Disparador', + }, + }, +}; + +// Custom business terminology example (English but with different terms) +const businessTerminology = { + markdown: { + sections: { + methods: 'Business Operations', + properties: 'Business Attributes', + fields: 'Data Elements', + constructors: 'Initializers', + }, + details: { + parameters: 'Input Parameters', + returnType: 'Output Type', + }, + typeSuffixes: { + class: 'Service', + interface: 'Contract', + }, + }, +}; + +// Partial translations example - only override specific terms +const partialTranslations = { + changelog: { + title: 'Change History', // Only override the title + }, + markdown: { + sections: { + methods: 'Functions', // Use "Functions" instead of "Methods" + }, + }, +}; + +export default { + // Example 1: Spanish documentation + spanish: defineMarkdownConfig({ + sourceDir: 'src', + targetDir: 'docs-es', + scope: ['public', 'global'], + translations: spanishTranslations, + }), + + // Example 2: Custom business terminology + business: defineMarkdownConfig({ + sourceDir: 'src', + targetDir: 'docs-business', + scope: ['public', 'global'], + translations: businessTerminology, + }), + + // Example 3: Partial translations (most text remains in English) + partial: defineMarkdownConfig({ + sourceDir: 'src', + targetDir: 'docs-partial', + scope: ['public', 'global'], + translations: partialTranslations, + }), + + // Example 4: Changelog with Spanish translations + changelogSpanish: defineChangelogConfig({ + previousVersionDir: 'previous', + currentVersionDir: 'current', + targetDir: 'changelog-es', + fileName: 'CAMBIOS', + scope: ['public', 'global'], + translations: spanishTranslations, + }), + + // Example 5: No translations (uses defaults) + default: defineMarkdownConfig({ + sourceDir: 'src', + targetDir: 'docs-default', + scope: ['public', 'global'], + // No translations property - will use English defaults + }), +}; diff --git a/src/core/changelog/generate-change-log.ts b/src/core/changelog/generate-change-log.ts index 480c7d7f..c141a74d 100644 --- a/src/core/changelog/generate-change-log.ts +++ b/src/core/changelog/generate-change-log.ts @@ -7,6 +7,7 @@ import { UnparsedSourceBundle, UserDefinedChangelogConfig, } from '../shared/types'; +import { mergeTranslations } from '../translations'; import { pipe } from 'fp-ts/function'; import * as TE from 'fp-ts/TaskEither'; import { reflectApexSource } from '../reflection/apex/reflect-apex-source'; @@ -38,8 +39,11 @@ export function generateChangeLog( if (config.skipIfNoChanges && !hasChanges(changelog)) { return skip(); } - return pipe(convertToRenderableChangelog(changelog, newManifest.types), compile, (content) => - convertToPageData(content, changelog), + const translations = mergeTranslations(config.translations); + return pipe( + convertToRenderableChangelog(changelog, newManifest.types, translations), + compile(translations), + (content) => convertToPageData(content, changelog), ); } @@ -105,13 +109,18 @@ function toManifests({ oldVersion, newVersion }: { oldVersion: ParsedFile[]; new }; } -function compile(renderable: RenderableChangelog): string { - const compilationRequest: CompilationRequest = { - template: changelogTemplate, - source: renderable, - }; +function compile(translations: ReturnType) { + return (renderable: RenderableChangelog): string => { + const compilationRequest: CompilationRequest = { + template: changelogTemplate, + source: { + ...renderable, + title: translations.changelog.title, + }, + }; - return Template.getInstance().compile(compilationRequest); + return Template.getInstance().compile(compilationRequest); + }; } function toPageData(fileName: string, content: string, changelog: Changelog): ChangeLogPageData { diff --git a/src/core/changelog/renderable-changelog.ts b/src/core/changelog/renderable-changelog.ts index dac5f1c8..4e68f44d 100644 --- a/src/core/changelog/renderable-changelog.ts +++ b/src/core/changelog/renderable-changelog.ts @@ -3,6 +3,7 @@ import { ClassMirror, EnumMirror, InterfaceMirror, Type } from '@cparra/apex-ref import { RenderableContent } from '../renderables/types'; import { adaptDescribable } from '../renderables/documentables'; import { CustomObjectMetadata } from '../reflection/sobject/reflect-custom-object-sources'; +import { Translations } from '../translations'; type NewTypeRenderable = { name: string; @@ -56,7 +57,11 @@ export type RenderableChangelog = { removedTriggers: NewOrRemovedTriggerSection | null; }; -export function convertToRenderableChangelog(changelog: Changelog, newManifest: ParsedType[]): RenderableChangelog { +export function convertToRenderableChangelog( + changelog: Changelog, + newManifest: ParsedType[], + translations: Translations, +): RenderableChangelog { const allNewTypes = [...changelog.newApexTypes, ...changelog.newCustomObjects].map( (newType) => newManifest.find((type) => type.name.toLowerCase() === newType.toLowerCase())!, ); @@ -83,8 +88,8 @@ export function convertToRenderableChangelog(changelog: Changelog, newManifest: newClasses.length > 0 ? { __type: 'class', - heading: 'New Classes', - description: 'These classes are new.', + heading: translations.changelog.newClasses.heading, + description: translations.changelog.newClasses.description, types: newClasses.map(typeToRenderable), } : null, @@ -92,8 +97,8 @@ export function convertToRenderableChangelog(changelog: Changelog, newManifest: newInterfaces.length > 0 ? { __type: 'interface', - heading: 'New Interfaces', - description: 'These interfaces are new.', + heading: translations.changelog.newInterfaces.heading, + description: translations.changelog.newInterfaces.description, types: newInterfaces.map(typeToRenderable), } : null, @@ -101,29 +106,35 @@ export function convertToRenderableChangelog(changelog: Changelog, newManifest: newEnums.length > 0 ? { __type: 'enum', - heading: 'New Enums', - description: 'These enums are new.', + heading: translations.changelog.newEnums.heading, + description: translations.changelog.newEnums.description, types: newEnums.map(typeToRenderable), } : null, removedTypes: changelog.removedApexTypes.length > 0 - ? { heading: 'Removed Types', description: 'These types have been removed.', types: changelog.removedApexTypes } + ? { + heading: translations.changelog.removedTypes.heading, + description: translations.changelog.removedTypes.description, + types: changelog.removedApexTypes, + } : null, newOrModifiedMembers: changelog.newOrModifiedApexMembers.length > 0 ? { - heading: 'New or Modified Members in Existing Types', - description: 'These members have been added or modified.', - modifications: changelog.newOrModifiedApexMembers.map(toRenderableModification), + heading: translations.changelog.newOrModifiedMembers.heading, + description: translations.changelog.newOrModifiedMembers.description, + modifications: changelog.newOrModifiedApexMembers.map((member) => + toRenderableModification(member, translations), + ), } : null, newCustomObjects: newCustomObjects.length > 0 ? { __type: 'customobject', - heading: 'New Custom Objects', - description: 'These custom objects are new.', + heading: translations.changelog.newCustomObjects.heading, + description: translations.changelog.newCustomObjects.description, types: newCustomObjects.map((type) => ({ name: type.name, description: type.description ? [type.description] : undefined, @@ -133,32 +144,34 @@ export function convertToRenderableChangelog(changelog: Changelog, newManifest: removedCustomObjects: changelog.removedCustomObjects.length > 0 ? { - heading: 'Removed Custom Objects', - description: 'These custom objects have been removed.', + heading: translations.changelog.removedCustomObjects.heading, + description: translations.changelog.removedCustomObjects.description, types: changelog.removedCustomObjects, } : null, newOrRemovedCustomFields: newOrModifiedCustomFields.length > 0 ? { - heading: 'New or Removed Fields to Custom Objects or Standard Objects', - description: 'These custom fields have been added or removed.', - modifications: newOrModifiedCustomFields.map(toRenderableModification), + heading: translations.changelog.newOrRemovedCustomFields.heading, + description: translations.changelog.newOrRemovedCustomFields.description, + modifications: newOrModifiedCustomFields.map((member) => toRenderableModification(member, translations)), } : null, newOrRemovedCustomMetadataTypeRecords: newOrModifiedCustomMetadataTypeRecords.length > 0 ? { - heading: 'New or Removed Custom Metadata Type Records', - description: 'These custom metadata type records have been added or removed.', - modifications: newOrModifiedCustomMetadataTypeRecords.map(toRenderableModification), + heading: translations.changelog.newOrRemovedCustomMetadataTypeRecords.heading, + description: translations.changelog.newOrRemovedCustomMetadataTypeRecords.description, + modifications: newOrModifiedCustomMetadataTypeRecords.map((member) => + toRenderableModification(member, translations), + ), } : null, newTriggers: changelog.newTriggers.length > 0 ? { - heading: 'New Triggers', - description: 'These triggers are new.', + heading: translations.changelog.newTriggers.heading, + description: translations.changelog.newTriggers.description, triggerData: changelog.newTriggers.map((trigger) => ({ triggerName: trigger.triggerName, objectName: trigger.objectName, @@ -168,8 +181,8 @@ export function convertToRenderableChangelog(changelog: Changelog, newManifest: removedTriggers: changelog.removedTriggers.length > 0 ? { - heading: 'Removed Triggers', - description: 'These triggers have been removed.', + heading: translations.changelog.removedTriggers.heading, + description: translations.changelog.removedTriggers.description, triggerData: changelog.removedTriggers.map((trigger) => ({ triggerName: trigger.triggerName, objectName: trigger.objectName, @@ -191,14 +204,22 @@ function typeToRenderable(type: Type): NewTypeRenderable { }; } -function toRenderableModification(newOrModifiedMember: NewOrModifiedMember): NewOrModifiedMemberSection { +function toRenderableModification( + newOrModifiedMember: NewOrModifiedMember, + translations: Translations, +): NewOrModifiedMemberSection { return { typeName: newOrModifiedMember.typeName, - modifications: newOrModifiedMember.modifications.map(toRenderableModificationDescription), + modifications: newOrModifiedMember.modifications.map((mod) => + toRenderableModificationDescription(mod, translations), + ), }; } -function toRenderableModificationDescription(memberModificationType: MemberModificationType): string { +function toRenderableModificationDescription( + memberModificationType: MemberModificationType, + translations: Translations, +): string { function withDescription(memberModificationType: MemberModificationType): string { if (memberModificationType.description) { return `${memberModificationType.name}. ${memberModificationType.description}`; @@ -208,32 +229,32 @@ function toRenderableModificationDescription(memberModificationType: MemberModif switch (memberModificationType.__typename) { case 'NewEnumValue': - return `New Enum Value: ${withDescription(memberModificationType)}`; + return `${translations.changelog.memberModifications.newEnumValue}: ${withDescription(memberModificationType)}`; case 'RemovedEnumValue': - return `Removed Enum Value: ${memberModificationType.name}`; + return `${translations.changelog.memberModifications.removedEnumValue}: ${memberModificationType.name}`; case 'NewMethod': - return `New Method: ${withDescription(memberModificationType)}`; + return `${translations.changelog.memberModifications.newMethod}: ${withDescription(memberModificationType)}`; case 'RemovedMethod': - return `Removed Method: ${memberModificationType.name}`; + return `${translations.changelog.memberModifications.removedMethod}: ${memberModificationType.name}`; case 'NewProperty': - return `New Property: ${withDescription(memberModificationType)}`; + return `${translations.changelog.memberModifications.newProperty}: ${withDescription(memberModificationType)}`; case 'RemovedProperty': - return `Removed Property: ${memberModificationType.name}`; + return `${translations.changelog.memberModifications.removedProperty}: ${memberModificationType.name}`; case 'NewField': - return `New Field: ${withDescription(memberModificationType)}`; + return `${translations.changelog.memberModifications.newField}: ${withDescription(memberModificationType)}`; case 'RemovedField': - return `Removed Field: ${memberModificationType.name}`; + return `${translations.changelog.memberModifications.removedField}: ${memberModificationType.name}`; case 'NewType': - return `New Type: ${withDescription(memberModificationType)}`; + return `${translations.changelog.memberModifications.newType}: ${withDescription(memberModificationType)}`; case 'RemovedType': - return `Removed Type: ${memberModificationType.name}`; + return `${translations.changelog.memberModifications.removedType}: ${memberModificationType.name}`; case 'NewCustomMetadataRecord': - return `New Custom Metadata Record: ${withDescription(memberModificationType)}`; + return `${translations.changelog.memberModifications.newCustomMetadataRecord}: ${withDescription(memberModificationType)}`; case 'RemovedCustomMetadataRecord': - return `Removed Custom Metadata Record: ${memberModificationType.name}`; + return `${translations.changelog.memberModifications.removedCustomMetadataRecord}: ${memberModificationType.name}`; case 'NewTrigger': - return `New Trigger: ${withDescription(memberModificationType)}`; + return `${translations.changelog.memberModifications.newTrigger}: ${withDescription(memberModificationType)}`; case 'RemovedTrigger': - return `Removed Trigger: ${memberModificationType.name}`; + return `${translations.changelog.memberModifications.removedTrigger}: ${memberModificationType.name}`; } } diff --git a/src/core/changelog/templates/changelog-template.ts b/src/core/changelog/templates/changelog-template.ts index d09d3fed..65267111 100644 --- a/src/core/changelog/templates/changelog-template.ts +++ b/src/core/changelog/templates/changelog-template.ts @@ -1,5 +1,5 @@ export const changelogTemplate = ` -# Changelog +# {{#if title}}{{title}}{{else}}Changelog{{/if}} {{#if newClasses}} ## {{newClasses.heading}} diff --git a/src/core/markdown/adapters/__tests__/interface-adapter.spec.ts b/src/core/markdown/adapters/__tests__/interface-adapter.spec.ts index 9c0d9bdb..e5851f6f 100644 --- a/src/core/markdown/adapters/__tests__/interface-adapter.spec.ts +++ b/src/core/markdown/adapters/__tests__/interface-adapter.spec.ts @@ -3,6 +3,7 @@ import { InterfaceMirrorBuilder } from '../../../../test-helpers/InterfaceMirror import { AnnotationBuilder } from '../../../../test-helpers/AnnotationBuilder'; import { MethodMirrorBuilder, ParameterBuilder } from '../../../../test-helpers/MethodMirrorBuilder'; import { MarkdownGeneratorConfig } from '../../generate-docs'; +import { defaultTranslations } from '../../../translations'; function linkGenerator(type: string): string { return type; @@ -40,6 +41,7 @@ describe('Conversion from InterfaceMirror to InterfaceSource understandable by t }, linkGenerator, defaultMarkdownGeneratorConfig, + defaultTranslations, ); expect(interfaceSource.name).toBe('SampleInterface'); @@ -58,6 +60,7 @@ describe('Conversion from InterfaceMirror to InterfaceSource understandable by t }, linkGenerator, defaultMarkdownGeneratorConfig, + defaultTranslations, ); expect(interfaceSource.meta.accessModifier).toBe('public'); @@ -78,6 +81,7 @@ describe('Conversion from InterfaceMirror to InterfaceSource understandable by t }, linkGenerator, defaultMarkdownGeneratorConfig, + defaultTranslations, ); expect(interfaceSource.doc.annotations).toEqual(['MYANNOTATION']); @@ -107,6 +111,7 @@ describe('Conversion from InterfaceMirror to InterfaceSource understandable by t }, linkGenerator, defaultMarkdownGeneratorConfig, + defaultTranslations, ); expect(interfaceSource.methods.value).toHaveLength(1); @@ -146,6 +151,7 @@ describe('Conversion from InterfaceMirror to InterfaceSource understandable by t }, linkGenerator, defaultMarkdownGeneratorConfig, + defaultTranslations, ); expect(interfaceSource.methods.value).toHaveLength(1); diff --git a/src/core/markdown/adapters/fields-and-properties.ts b/src/core/markdown/adapters/fields-and-properties.ts index 500fe5cc..ecb7d879 100644 --- a/src/core/markdown/adapters/fields-and-properties.ts +++ b/src/core/markdown/adapters/fields-and-properties.ts @@ -6,11 +6,13 @@ import { GetRenderableContentByTypeName, } from '../../renderables/types'; import { adaptDocumentable } from '../../renderables/documentables'; +import { Translations } from '../../translations'; export function adaptFieldOrProperty( field: FieldMirrorWithInheritance | PropertyMirrorWithInheritance, linkGenerator: GetRenderableContentByTypeName, baseHeadingLevel: number, + translations: Translations, ): RenderableApexField { function buildSignature(): CodeBlock { const { access_modifier, name } = field; @@ -31,14 +33,14 @@ export function adaptFieldOrProperty( heading: field.name, type: { headingLevel: baseHeadingLevel + 1, - heading: 'Type', + heading: translations.markdown.details.type, value: linkGenerator(field.typeReference.rawDeclaration), }, inherited: field.inherited, accessModifier: field.access_modifier, signature: { headingLevel: baseHeadingLevel + 1, - heading: 'Signature', + heading: translations.markdown.details.signature, value: buildSignature(), }, }; diff --git a/src/core/markdown/adapters/methods-and-constructors.ts b/src/core/markdown/adapters/methods-and-constructors.ts index 4a749de3..cc966d17 100644 --- a/src/core/markdown/adapters/methods-and-constructors.ts +++ b/src/core/markdown/adapters/methods-and-constructors.ts @@ -8,11 +8,13 @@ import { } from '../../renderables/types'; import { adaptDescribable, adaptDocumentable } from '../../renderables/documentables'; import { Documentable } from '../../renderables/types'; +import { Translations } from '../../translations'; export function adaptMethod( method: MethodMirror, linkGenerator: GetRenderableContentByTypeName, baseHeadingLevel: number, + translations: Translations, ): RenderableMethod { function buildTitle(method: MethodMirrorWithInheritance): string { const { name, parameters } = method; @@ -39,12 +41,12 @@ export function adaptMethod( heading: buildTitle(method as MethodMirrorWithInheritance), signature: { headingLevel: baseHeadingLevel + 1, - heading: 'Signature', + heading: translations.markdown.details.signature, value: buildSignature(method as MethodMirrorWithInheritance), }, returnType: { headingLevel: baseHeadingLevel + 1, - heading: 'Return Type', + heading: translations.markdown.details.returnType, value: { ...adaptDescribable(method.docComment?.returnAnnotation?.bodyLines, linkGenerator), type: linkGenerator(method.typeReference.rawDeclaration), @@ -52,12 +54,12 @@ export function adaptMethod( }, throws: { headingLevel: baseHeadingLevel + 1, - heading: 'Throws', + heading: translations.markdown.details.throws, value: method.docComment?.throwsAnnotations.map((thrown) => mapThrows(thrown, linkGenerator)), }, parameters: { headingLevel: baseHeadingLevel + 1, - heading: 'Parameters', + heading: translations.markdown.details.parameters, value: method.parameters.map((param) => mapParameters(method, param, linkGenerator)), }, inherited: (method as MethodMirrorWithInheritance).inherited, @@ -69,6 +71,7 @@ export function adaptConstructor( constructor: ConstructorMirror, linkGenerator: GetRenderableContentByTypeName, baseHeadingLevel: number, + translations: Translations, ): RenderableConstructor { function buildTitle(name: string, constructor: ConstructorMirror): string { const { parameters } = constructor; @@ -94,17 +97,17 @@ export function adaptConstructor( heading: buildTitle(typeName, constructor), signature: { headingLevel: baseHeadingLevel + 1, - heading: 'Signature', + heading: translations.markdown.details.signature, value: buildSignature(typeName, constructor), }, parameters: { headingLevel: baseHeadingLevel + 1, - heading: 'Parameters', + heading: translations.markdown.details.parameters, value: constructor.parameters.map((param) => mapParameters(constructor, param, linkGenerator)), }, throws: { headingLevel: baseHeadingLevel + 1, - heading: 'Throws', + heading: translations.markdown.details.throws, value: constructor.docComment?.throwsAnnotations.map((thrown) => mapThrows(thrown, linkGenerator)), }, }; diff --git a/src/core/markdown/adapters/renderable-bundle.ts b/src/core/markdown/adapters/renderable-bundle.ts index 0b079e48..887e6d7a 100644 --- a/src/core/markdown/adapters/renderable-bundle.ts +++ b/src/core/markdown/adapters/renderable-bundle.ts @@ -12,11 +12,13 @@ import { MarkdownGeneratorConfig } from '../generate-docs'; import { apply } from '#utils/fp'; import { generateLink } from './generate-link'; import { getTypeGroup } from '../../shared/utils'; +import { Translations } from '../../translations'; export function parsedFilesToRenderableBundle( config: MarkdownGeneratorConfig, parsedFiles: ParsedFile[], references: Record, + translations: Translations, ): RenderableBundle { const referenceFinder = apply(generateLink(config.linkingStrategy), references); @@ -29,7 +31,12 @@ export function parsedFilesToRenderableBundle( function toRenderables(parsedFiles: ParsedFile[]): Renderable[] { return parsedFiles.reduce((acc, parsedFile) => { - const renderable = typeToRenderable(parsedFile, apply(referenceFinder, parsedFile.source.name), config); + const renderable = typeToRenderable( + parsedFile, + apply(referenceFinder, parsedFile.source.name), + config, + translations, + ); acc.push(renderable); return acc; }, []); diff --git a/src/core/markdown/adapters/renderable-to-page-data.ts b/src/core/markdown/adapters/renderable-to-page-data.ts index c60171be..b1cc878e 100644 --- a/src/core/markdown/adapters/renderable-to-page-data.ts +++ b/src/core/markdown/adapters/renderable-to-page-data.ts @@ -8,10 +8,12 @@ import { classMarkdownTemplate } from '../templates/class-template'; import { markdownDefaults } from '../../../defaults'; import { customObjectTemplate } from '../templates/custom-object-template'; import { triggerMarkdownTemplate } from '../templates/trigger-template'; +import { Translations } from '../../translations'; export const convertToDocumentationBundle = ( referenceGuideTitle: string, referenceGuideTemplate: string, + translations: Translations, { referencesByGroup, renderables }: RenderableBundle, ): DocumentationBundle => ({ referenceGuide: { @@ -20,7 +22,7 @@ export const convertToDocumentationBundle = ( outputDocPath: 'index.md', }, docs: renderables.map((renderable: Renderable) => - renderableToPageData(Object.values(referencesByGroup).flat(), renderable), + renderableToPageData(Object.values(referencesByGroup).flat(), renderable, translations), ), }); @@ -48,7 +50,11 @@ function referencesToReferenceGuideContent( ); } -function renderableToPageData(referenceGuideReference: ReferenceGuideReference[], renderable: Renderable): DocPageData { +function renderableToPageData( + referenceGuideReference: ReferenceGuideReference[], + renderable: Renderable, + translations: Translations, +): DocPageData { function buildDocOutput(renderable: Renderable, docContents: string): DocPageData { const reference: ReferenceGuideReference = referenceGuideReference.find( (ref) => ref.reference.source.name.toLowerCase() === renderable.name.toLowerCase(), @@ -68,10 +74,15 @@ function renderableToPageData(referenceGuideReference: ReferenceGuideReference[] }; } - return pipe(renderable, resolveApexTypeTemplate, compile, (docContents) => buildDocOutput(renderable, docContents)); + return pipe( + renderable, + (r) => resolveApexTypeTemplate(r, translations), + compile, + (docContents) => buildDocOutput(renderable, docContents), + ); } -function resolveApexTypeTemplate(renderable: Renderable): CompilationRequest { +function resolveApexTypeTemplate(renderable: Renderable, translations: Translations): CompilationRequest { function getTemplate(renderable: Renderable): string { switch (renderable.type) { case 'enum': @@ -89,7 +100,10 @@ function resolveApexTypeTemplate(renderable: Renderable): CompilationRequest { return { template: getTemplate(renderable), - source: renderable as RenderableEnum, + source: { + ...(renderable as RenderableEnum), + translations, + }, }; } diff --git a/src/core/markdown/adapters/type-to-renderable.ts b/src/core/markdown/adapters/type-to-renderable.ts index ca7995c3..a5c00b44 100644 --- a/src/core/markdown/adapters/type-to-renderable.ts +++ b/src/core/markdown/adapters/type-to-renderable.ts @@ -25,6 +25,7 @@ import { getTypeGroup, isInSource } from '../../shared/utils'; import { CustomFieldMetadata } from '../../reflection/sobject/reflect-custom-field-source'; import { CustomMetadataMetadata } from '../../reflection/sobject/reflect-custom-metadata-source'; import { TriggerMetadata } from 'src/core/reflection/trigger/reflect-trigger-source'; +import { Translations } from '../../translations'; type GetReturnRenderable = T extends InterfaceMirror ? RenderableInterface @@ -40,6 +41,7 @@ export function typeToRenderable( parsedFile: { source: SourceFileMetadata | ExternalMetadata; type: T }, linkGenerator: GetRenderableContentByTypeName, config: MarkdownGeneratorConfig, + translations: Translations, ): GetReturnRenderable & { filePath: string | undefined; namespace?: string } { function getRenderable(): | RenderableInterface @@ -50,15 +52,15 @@ export function typeToRenderable( const { type } = parsedFile; switch (type.type_name) { case 'enum': - return enumTypeToEnumSource(type as EnumMirror, linkGenerator); + return enumTypeToEnumSource(type as EnumMirror, linkGenerator, 1, translations); case 'interface': - return interfaceTypeToInterfaceSource(type as InterfaceMirror, linkGenerator); + return interfaceTypeToInterfaceSource(type as InterfaceMirror, linkGenerator, 1, translations); case 'class': - return classTypeToClassSource(type as ClassMirrorWithInheritanceChain, linkGenerator); + return classTypeToClassSource(type as ClassMirrorWithInheritanceChain, linkGenerator, 1, translations); case 'trigger': - return triggerMetadataToRenderable(type as TriggerMetadata, linkGenerator); + return triggerMetadataToRenderable(type as TriggerMetadata, linkGenerator, 1, translations); case 'customobject': - return objectMetadataToRenderable(type as CustomObjectMetadata, config); + return objectMetadataToRenderable(type as CustomObjectMetadata, config, translations); } } @@ -73,12 +75,13 @@ function baseTypeAdapter( type: EnumMirror | InterfaceMirror | ClassMirror, linkGenerator: GetRenderableContentByTypeName, baseHeadingLevel: number, + translations: Translations, ): RenderableType { function getHeading(type: Type): string { const suffixMap = { - class: 'Class', - interface: 'Interface', - enum: 'Enum', + class: translations.markdown.typeSuffixes.class, + interface: translations.markdown.typeSuffixes.interface, + enum: translations.markdown.typeSuffixes.enum, }; return `${type.name} ${suffixMap[type.type_name]}`; @@ -99,13 +102,14 @@ function enumTypeToEnumSource( enumType: EnumMirror, linkGenerator: GetRenderableContentByTypeName, baseHeadingLevel: number = 1, + translations: Translations, ): RenderableEnum { return { type: 'enum', - ...baseTypeAdapter(enumType, linkGenerator, baseHeadingLevel), + ...baseTypeAdapter(enumType, linkGenerator, baseHeadingLevel, translations), values: { headingLevel: baseHeadingLevel + 1, - heading: 'Values', + heading: translations.markdown.sections.values, value: enumType.values.map((value) => ({ ...adaptDescribable(value.docComment?.descriptionLines, linkGenerator), value: value.name, @@ -118,15 +122,18 @@ function interfaceTypeToInterfaceSource( interfaceType: InterfaceMirror, linkGenerator: GetRenderableContentByTypeName, baseHeadingLevel: number = 1, + translations: Translations, ): RenderableInterface { return { type: 'interface', - ...baseTypeAdapter(interfaceType, linkGenerator, baseHeadingLevel), + ...baseTypeAdapter(interfaceType, linkGenerator, baseHeadingLevel, translations), extends: interfaceType.extended_interfaces.map(linkGenerator), methods: { headingLevel: baseHeadingLevel + 1, - heading: 'Methods', - value: interfaceType.methods.map((method) => adaptMethod(method, linkGenerator, baseHeadingLevel + 2)), + heading: translations.markdown.sections.methods, + value: interfaceType.methods.map((method) => + adaptMethod(method, linkGenerator, baseHeadingLevel + 2, translations), + ), }, }; } @@ -135,54 +142,72 @@ function classTypeToClassSource( classType: ClassMirrorWithInheritanceChain, linkGenerator: GetRenderableContentByTypeName, baseHeadingLevel: number = 1, + translations: Translations, ): RenderableClass { return { type: 'class', - ...baseTypeAdapter(classType, linkGenerator, baseHeadingLevel), + ...baseTypeAdapter(classType, linkGenerator, baseHeadingLevel, translations), classModifier: classType.classModifier, sharingModifier: classType.sharingModifier, implements: classType.implemented_interfaces.map(linkGenerator), extends: classType.inheritanceChain.map(linkGenerator), - methods: adaptMembers('Methods', classType.methods, adaptMethod, linkGenerator, baseHeadingLevel + 1), + methods: adaptMembers( + translations.markdown.sections.methods, + classType.methods, + adaptMethod, + linkGenerator, + baseHeadingLevel + 1, + translations, + ), constructors: adaptMembers( - 'Constructors', + translations.markdown.sections.constructors, classType.constructors, - (constructor, linkGenerator, baseHeadingLevel) => - adaptConstructor(classType.name, constructor, linkGenerator, baseHeadingLevel), + (constructor, linkGenerator, baseHeadingLevel, translations) => + adaptConstructor(classType.name, constructor, linkGenerator, baseHeadingLevel, translations), linkGenerator, baseHeadingLevel + 1, + translations, ), fields: adaptMembers( - 'Fields', + translations.markdown.sections.fields, classType.fields as FieldMirrorWithInheritance[], adaptFieldOrProperty, linkGenerator, baseHeadingLevel + 1, + translations, ), properties: adaptMembers( - 'Properties', + translations.markdown.sections.properties, classType.properties as PropertyMirrorWithInheritance[], adaptFieldOrProperty, linkGenerator, baseHeadingLevel + 1, + translations, ), innerClasses: { headingLevel: baseHeadingLevel + 1, - heading: 'Classes', + heading: translations.markdown.sections.classes, value: classType.classes.map((innerClass) => - classTypeToClassSource({ ...innerClass, inheritanceChain: [] }, linkGenerator, baseHeadingLevel + 2), + classTypeToClassSource( + { ...innerClass, inheritanceChain: [] }, + linkGenerator, + baseHeadingLevel + 2, + translations, + ), ), }, innerEnums: { headingLevel: baseHeadingLevel + 1, - heading: 'Enums', - value: classType.enums.map((innerEnum) => enumTypeToEnumSource(innerEnum, linkGenerator, baseHeadingLevel + 2)), + heading: translations.markdown.sections.enums, + value: classType.enums.map((innerEnum) => + enumTypeToEnumSource(innerEnum, linkGenerator, baseHeadingLevel + 2, translations), + ), }, innerInterfaces: { headingLevel: baseHeadingLevel + 1, - heading: 'Interfaces', + heading: translations.markdown.sections.interfaces, value: classType.interfaces.map((innerInterface) => - interfaceTypeToInterfaceSource(innerInterface, linkGenerator, baseHeadingLevel + 2), + interfaceTypeToInterfaceSource(innerInterface, linkGenerator, baseHeadingLevel + 2, translations), ), }, }; @@ -193,17 +218,23 @@ type Groupable = { group?: string; groupDescription?: string }; function adaptMembers( heading: string, members: T[], - adapter: (member: T, linkGenerator: GetRenderableContentByTypeName, baseHeadingLevel: number) => K, + adapter: ( + member: T, + linkGenerator: GetRenderableContentByTypeName, + baseHeadingLevel: number, + translations: Translations, + ) => K, linkFromTypeNameGenerator: GetRenderableContentByTypeName, headingLevel: number, + translations: Translations, ): RenderableSection[]> & { isGrouped: boolean } { return { headingLevel, heading, isGrouped: hasGroup(members), value: hasGroup(members) - ? toGroupedMembers(members, adapter, linkFromTypeNameGenerator, headingLevel + 1) - : toFlat(members, adapter, linkFromTypeNameGenerator, headingLevel + 1), + ? toGroupedMembers(members, adapter, linkFromTypeNameGenerator, headingLevel + 1, translations) + : toFlat(members, adapter, linkFromTypeNameGenerator, headingLevel + 1, translations), }; } @@ -213,22 +244,34 @@ function hasGroup(members: Groupable[]): boolean { function toFlat( members: T[], - adapter: (member: T, linkGenerator: GetRenderableContentByTypeName, baseHeadingLevel: number) => K, + adapter: ( + member: T, + linkGenerator: GetRenderableContentByTypeName, + baseHeadingLevel: number, + translations: Translations, + ) => K, linkGenerator: GetRenderableContentByTypeName, baseHeadingLevel: number, + translations: Translations, ): K[] { - return members.map((member) => adapter(member, linkGenerator, baseHeadingLevel)); + return members.map((member) => adapter(member, linkGenerator, baseHeadingLevel, translations)); } function toGroupedMembers( members: T[], - adapter: (member: T, linkGenerator: GetRenderableContentByTypeName, baseHeadingLevel: number) => K, + adapter: ( + member: T, + linkGenerator: GetRenderableContentByTypeName, + baseHeadingLevel: number, + translations: Translations, + ) => K, linkGenerator: GetRenderableContentByTypeName, baseHeadingLevel: number, + translations: Translations, ): GroupedMember[] { const groupedMembers = groupByGroupName(members); return Object.entries(groupedMembers).map(([groupName, members]) => - singleGroup(baseHeadingLevel, groupName, adapter, members, linkGenerator), + singleGroup(baseHeadingLevel, groupName, adapter, members, linkGenerator, translations), ); } @@ -247,15 +290,21 @@ function groupByGroupName(members: T[]): Record( headingLevel: number, groupName: string, - adapter: (member: T, linkGenerator: GetRenderableContentByTypeName, baseHeadingLevel: number) => K, + adapter: ( + member: T, + linkGenerator: GetRenderableContentByTypeName, + baseHeadingLevel: number, + translations: Translations, + ) => K, members: T[], linkGenerator: GetRenderableContentByTypeName, + translations: Translations, ): GroupedMember { return { headingLevel: headingLevel, heading: groupName, groupDescription: members[0].groupDescription, // All fields in the group have the same description - value: toFlat(members, adapter, linkGenerator, headingLevel + 1), + value: toFlat(members, adapter, linkGenerator, headingLevel + 1, translations), }; } @@ -263,23 +312,24 @@ function triggerMetadataToRenderable( triggerMetadata: TriggerMetadata, linkGenerator: GetRenderableContentByTypeName, baseHeadingLevel: number = 1, + translations: Translations, ): RenderableTrigger { function formatEvent(event: string): string { switch (event) { case 'beforeinsert': - return 'Before Insert'; + return translations.markdown.triggerEvents.beforeInsert; case 'beforeupdate': - return 'Before Update'; + return translations.markdown.triggerEvents.beforeUpdate; case 'beforedelete': - return 'Before Delete'; + return translations.markdown.triggerEvents.beforeDelete; case 'afterinsert': - return 'After Insert'; + return translations.markdown.triggerEvents.afterInsert; case 'afterupdate': - return 'After Update'; + return translations.markdown.triggerEvents.afterUpdate; case 'afterdelete': - return 'After Delete'; + return translations.markdown.triggerEvents.afterDelete; case 'afterundelete': - return 'After Undelete'; + return translations.markdown.triggerEvents.afterUndelete; default: return event; } @@ -297,7 +347,7 @@ function triggerMetadataToRenderable( name: triggerMetadata.name, type: 'trigger', headingLevel: 1, - heading: triggerMetadata.name + ' Trigger', + heading: triggerMetadata.name + ' ' + translations.markdown.typeSuffixes.trigger, objectName: triggerMetadata.object_name, events: triggerMetadata.events.map(formatEvent), }; @@ -306,13 +356,14 @@ function triggerMetadataToRenderable( function objectMetadataToRenderable( objectMetadata: CustomObjectMetadata, config: MarkdownGeneratorConfig, + translations: Translations, ): RenderableCustomObject { function toRenderablePublishBehavior(publishBehavior: PublishBehavior | undefined): string | null { switch (publishBehavior) { case 'PublishImmediately': - return 'Publish Immediately'; + return translations.markdown.publishBehaviors.publishImmediately; case 'PublishAfterCommit': - return 'Publish After Commit'; + return translations.markdown.publishBehaviors.publishAfterCommit; default: return null; } @@ -331,13 +382,13 @@ function objectMetadataToRenderable( hasFields: objectMetadata.fields.length > 0, fields: { headingLevel: 2, - heading: 'Fields', - value: objectMetadata.fields.map((field) => fieldMetadataToRenderable(field, config, 3)), + heading: translations.markdown.sections.fields, + value: objectMetadata.fields.map((field) => fieldMetadataToRenderable(field, config, 3, translations)), }, hasRecords: objectMetadata.metadataRecords.length > 0, metadataRecords: { headingLevel: 2, - heading: 'Records', + heading: translations.markdown.sections.records, value: objectMetadata.metadataRecords.map((metadata) => customMetadataToRenderable(metadata, 3)), }, publishBehavior: toRenderablePublishBehavior(objectMetadata.publishBehavior), @@ -348,6 +399,7 @@ function fieldMetadataToRenderable( field: CustomFieldMetadata, config: MarkdownGeneratorConfig, headingLevel: number, + translations: Translations, ): RenderableCustomField { return { type: 'field', @@ -363,7 +415,7 @@ function fieldMetadataToRenderable( pickListValues: field.pickListValues ? { headingLevel: headingLevel + 1, - heading: 'Possible values are', + heading: translations.markdown.details.possibleValues, value: field.pickListValues, } : undefined, @@ -396,17 +448,16 @@ function getApiName(currentName: string, config: MarkdownGeneratorConfig) { } function renderComplianceGroup(complianceGroup: string | null, config: MarkdownGeneratorConfig) { - if(config.includeFieldSecurityMetadata) { + if (config.includeFieldSecurityMetadata) { return complianceGroup; } else { return null; } } function renderInlineHelpText(inlineHelpText: string | null, config: MarkdownGeneratorConfig) { - if(config.includeInlineHelpTextMetadata) { - return inlineHelpText + if (config.includeInlineHelpTextMetadata) { + return inlineHelpText; } else { return null; } } - diff --git a/src/core/markdown/generate-docs.ts b/src/core/markdown/generate-docs.ts index e7708918..84f436a6 100644 --- a/src/core/markdown/generate-docs.ts +++ b/src/core/markdown/generate-docs.ts @@ -19,6 +19,7 @@ import { TopLevelType, MacroFunction, } from '../shared/types'; +import { mergeTranslations } from '../translations'; import { parsedFilesToRenderableBundle } from './adapters/renderable-bundle'; import { reflectApexSource } from '../reflection/apex/reflect-apex-source'; import { addInheritanceChainToTypes } from '../reflection/apex/inheritance-chain-expanion'; @@ -48,12 +49,14 @@ export type MarkdownGeneratorConfig = Omit< }; export function generateDocs(unparsedBundles: UnparsedSourceBundle[], config: MarkdownGeneratorConfig) { + const translations = mergeTranslations(config.translations); const convertToReferences = apply(parsedFilesToReferenceGuide, config); const convertToRenderableBundle = apply(parsedFilesToRenderableBundle, config); const convertToDocumentationBundleForTemplate = apply( convertToDocumentationBundle, config.referenceGuideTitle, config.referenceGuideTemplate, + translations, ); const sort = apply(sortTypesAndMembers, config.sortAlphabetically); @@ -92,7 +95,7 @@ export function generateDocs(unparsedBundles: UnparsedSourceBundle[], config: Ma ), TE.flatMap(({ parsedFiles, references }) => transformReferenceHook(config)({ references, parsedFiles })), TE.map(({ parsedFiles, references }) => - convertToRenderableBundle(filterOutCustomFieldsAndMetadata(parsedFiles), references), + convertToRenderableBundle(filterOutCustomFieldsAndMetadata(parsedFiles), references, translations), ), TE.map(convertToDocumentationBundleForTemplate), TE.flatMap(transformDocumentationBundleHook(config)), diff --git a/src/core/markdown/templates/class-template.ts b/src/core/markdown/templates/class-template.ts index ec5b7a85..276beec0 100644 --- a/src/core/markdown/templates/class-template.ts +++ b/src/core/markdown/templates/class-template.ts @@ -7,13 +7,13 @@ export const classMarkdownTemplate = ` {{> typeDocumentation}} {{#if extends.length}} -**Inheritance** +**{{#if translations.markdown.inheritance.inheritance}}{{translations.markdown.inheritance.inheritance}}{{else}}Inheritance{{/if}}** {{#each extends}}{{link this}}{{#unless @last}} < {{/unless}}{{/each}} {{/if}} {{#if implements}} -**Implements** +**{{#if translations.markdown.inheritance.implements}}{{translations.markdown.inheritance.implements}}{{else}}Implements{{/if}}** {{#each implements}} {{link this}}{{#unless @last}}, {{/unless}} diff --git a/src/core/markdown/templates/custom-object-template.ts b/src/core/markdown/templates/custom-object-template.ts index 5686ed72..cf85d297 100644 --- a/src/core/markdown/templates/custom-object-template.ts +++ b/src/core/markdown/templates/custom-object-template.ts @@ -3,11 +3,11 @@ export const customObjectTemplate = ` {{{renderContent doc.description}}} -## API Name +## {{#if translations.markdown.details.apiName}}{{translations.markdown.details.apiName}}{{else}}API Name{{/if}} \`{{apiName}}\` {{#if publishBehavior}} -## Publish Behavior +## {{#if translations.markdown.sections.publishBehavior}}{{translations.markdown.sections.publishBehavior}}{{else}}Publish Behavior{{/if}} **{{publishBehavior}}** {{/if}} @@ -17,7 +17,7 @@ export const customObjectTemplate = ` {{#each fields.value}} {{ heading headingLevel heading }} {{#if required}} -**Required** +**{{#if translations.markdown.details.required}}{{translations.markdown.details.required}}{{else}}Required{{/if}}** {{/if}} {{#if description}} @@ -25,26 +25,26 @@ export const customObjectTemplate = ` {{/if}} {{#if inlineHelpText}} -**Inline Help Text** +**{{#if translations.markdown.details.inlineHelpText}}{{translations.markdown.details.inlineHelpText}}{{else}}Inline Help Text{{/if}}** {{inlineHelpText}} {{/if}} {{#if complianceGroup}} -**Compliance Group** +**{{#if translations.markdown.details.complianceGroup}}{{translations.markdown.details.complianceGroup}}{{else}}Compliance Group{{/if}}** {{complianceGroup}} {{/if}} {{#if securityClassification}} -**Security Classification** +**{{#if translations.markdown.details.securityClassification}}{{translations.markdown.details.securityClassification}}{{else}}Security Classification{{/if}}** {{securityClassification}} {{/if}} -**API Name** +**{{#if translations.markdown.details.apiName}}{{translations.markdown.details.apiName}}{{else}}API Name{{/if}}** \`{{{apiName}}}\` {{#if fieldType}} -**Type** +**{{#if translations.markdown.details.type}}{{translations.markdown.details.type}}{{else}}Type{{/if}}** *{{fieldType}}* @@ -66,14 +66,14 @@ export const customObjectTemplate = ` {{ heading headingLevel heading }} {{#if protected}} -\`Protected\` +\`{{#if translations.markdown.details.protected}}{{translations.markdown.details.protected}}{{else}}Protected{{/if}}\` {{/if}} {{#if description}} {{{renderContent description}}} {{/if}} -**API Name** +**{{#if translations.markdown.details.apiName}}{{translations.markdown.details.apiName}}{{else}}API Name{{/if}}** \`{{{apiName}}}\` diff --git a/src/core/markdown/templates/type-doc-partial.ts b/src/core/markdown/templates/type-doc-partial.ts index 25a04ce1..df1c4c61 100644 --- a/src/core/markdown/templates/type-doc-partial.ts +++ b/src/core/markdown/templates/type-doc-partial.ts @@ -2,24 +2,24 @@ export const typeDocPartial = ` {{#> documentablePartialTemplate}} {{#if doc.group}} -**Group** {{doc.group}} +**{{#if translations.markdown.details.group}}{{translations.markdown.details.group}}{{else}}Group{{/if}}** {{doc.group}} {{/if}} {{#if doc.author}} -**Author** {{doc.author}} +**{{#if translations.markdown.details.author}}{{translations.markdown.details.author}}{{else}}Author{{/if}}** {{doc.author}} {{/if}} {{#if doc.date}} -**Date** {{doc.date}} +**{{#if translations.markdown.details.date}}{{translations.markdown.details.date}}{{else}}Date{{/if}}** {{doc.date}} {{/if}} {{#each doc.sees}} -**See** {{link this}} +**{{#if ../translations.markdown.details.see}}{{../translations.markdown.details.see}}{{else}}See{{/if}}** {{link this}} {{/each}} {{#if namespace}} -## Namespace +## {{#if translations.markdown.sections.namespace}}{{translations.markdown.sections.namespace}}{{else}}Namespace{{/if}} {{namespace}} {{/if}} diff --git a/src/core/shared/types.d.ts b/src/core/shared/types.d.ts index cd4340f4..63186081 100644 --- a/src/core/shared/types.d.ts +++ b/src/core/shared/types.d.ts @@ -3,6 +3,7 @@ import { CustomObjectMetadata } from '../reflection/sobject/reflect-custom-objec import { CustomFieldMetadata } from '../reflection/sobject/reflect-custom-field-source'; import { CustomMetadataMetadata } from '../reflection/sobject/reflect-custom-metadata-source'; import { TriggerMetadata } from '../reflection/trigger/reflect-trigger-source'; +import { UserTranslations } from '../translations'; export type Generators = 'markdown' | 'openapi' | 'changelog'; @@ -48,6 +49,7 @@ export type UserDefinedMarkdownConfig = { targetGenerator: 'markdown'; excludeTags: string[]; exclude: string[]; + translations?: UserTranslations; } & CliConfigurableMarkdownConfig & Partial; @@ -74,6 +76,7 @@ export type UserDefinedChangelogConfig = { customObjectVisibility: string[]; exclude: string[]; skipIfNoChanges: boolean; + translations?: UserTranslations; } & Partial; export type UserDefinedConfig = UserDefinedMarkdownConfig | UserDefinedOpenApiConfig | UserDefinedChangelogConfig; diff --git a/src/core/translations/__tests__/translation-utils.test.ts b/src/core/translations/__tests__/translation-utils.test.ts new file mode 100644 index 00000000..837d0b83 --- /dev/null +++ b/src/core/translations/__tests__/translation-utils.test.ts @@ -0,0 +1,267 @@ +import { mergeTranslations, validateUserTranslations } from '../translation-utils'; +import { defaultTranslations } from '../default-translations'; + +describe('translation-utils', () => { + describe('mergeTranslations', () => { + it('should return default translations when no user translations provided', () => { + const result = mergeTranslations(); + expect(result).toEqual(defaultTranslations); + }); + + it('should return default translations when undefined is provided', () => { + const result = mergeTranslations(undefined); + expect(result).toEqual(defaultTranslations); + }); + + it('should merge partial user translations with defaults', () => { + const userTranslations = { + markdown: { + sections: { + methods: 'Functions', + }, + }, + }; + + const result = mergeTranslations(userTranslations); + + expect(result.markdown.sections.methods).toBe('Functions'); + expect(result.markdown.sections.properties).toBe('Properties'); // Should keep default + expect(result.changelog.title).toBe('Changelog'); // Should keep default + }); + + it('should completely override sections when provided', () => { + const userTranslations = { + changelog: { + title: 'Change History', + newClasses: { + heading: 'Added Classes', + description: 'These are the new classes.', + }, + }, + }; + + const result = mergeTranslations(userTranslations); + + expect(result.changelog.title).toBe('Change History'); + expect(result.changelog.newClasses.heading).toBe('Added Classes'); + expect(result.changelog.newClasses.description).toBe('These are the new classes.'); + // Should keep other defaults + expect(result.changelog.newInterfaces.heading).toBe('New Interfaces'); + }); + + it('should handle deep nested overrides', () => { + const userTranslations = { + markdown: { + details: { + parameters: 'Input Parameters', + returnType: 'Output Type', + }, + triggerEvents: { + beforeInsert: 'Antes de Insertar', + }, + }, + }; + + const result = mergeTranslations(userTranslations); + + expect(result.markdown.details.parameters).toBe('Input Parameters'); + expect(result.markdown.details.returnType).toBe('Output Type'); + expect(result.markdown.details.type).toBe('Type'); // Should keep default + expect(result.markdown.triggerEvents.beforeInsert).toBe('Antes de Insertar'); + expect(result.markdown.triggerEvents.beforeUpdate).toBe('Before Update'); // Should keep default + }); + + it('should handle complete translation replacement', () => { + const userTranslations = { + changelog: { + title: 'Registro de Cambios', + newClasses: { + heading: 'Nuevas Clases', + description: 'Estas clases son nuevas.', + }, + newInterfaces: { + heading: 'Nuevas Interfaces', + description: 'Estas interfaces son nuevas.', + }, + newEnums: { + heading: 'Nuevos Enums', + description: 'Estos enums son nuevos.', + }, + newCustomObjects: { + heading: 'Nuevos Objetos Personalizados', + description: 'Estos objetos personalizados son nuevos.', + }, + newTriggers: { + heading: 'Nuevos Disparadores', + description: 'Estos disparadores son nuevos.', + }, + removedTypes: { + heading: 'Tipos Eliminados', + description: 'Estos tipos han sido eliminados.', + }, + removedCustomObjects: { + heading: 'Objetos Personalizados Eliminados', + description: 'Estos objetos personalizados han sido eliminados.', + }, + removedTriggers: { + heading: 'Disparadores Eliminados', + description: 'Estos disparadores han sido eliminados.', + }, + newOrModifiedMembers: { + heading: 'Miembros Nuevos o Modificados en Tipos Existentes', + description: 'Estos miembros han sido agregados o modificados.', + }, + newOrRemovedCustomFields: { + heading: 'Campos Nuevos o Eliminados en Objetos Personalizados', + description: 'Estos campos personalizados han sido agregados o eliminados.', + }, + newOrRemovedCustomMetadataTypeRecords: { + heading: 'Registros de Tipos de Metadatos Personalizados Nuevos o Eliminados', + description: 'Estos registros de tipos de metadatos personalizados han sido agregados o eliminados.', + }, + memberModifications: { + newEnumValue: 'Nuevo Valor de Enum', + removedEnumValue: 'Valor de Enum Eliminado', + newMethod: 'Nuevo Método', + removedMethod: 'Método Eliminado', + newProperty: 'Nueva Propiedad', + removedProperty: 'Propiedad Eliminada', + newField: 'Nuevo Campo', + removedField: 'Campo Eliminado', + newType: 'Nuevo Tipo', + removedType: 'Tipo Eliminado', + newCustomMetadataRecord: 'Nuevo Registro de Metadatos Personalizados', + removedCustomMetadataRecord: 'Registro de Metadatos Personalizados Eliminado', + newTrigger: 'Nuevo Disparador', + removedTrigger: 'Disparador Eliminado', + }, + }, + markdown: { + sections: { + methods: 'Métodos', + properties: 'Propiedades', + fields: 'Campos', + constructors: 'Constructores', + values: 'Valores', + classes: 'Clases', + enums: 'Enums', + interfaces: 'Interfaces', + namespace: 'Espacio de Nombres', + records: 'Registros', + publishBehavior: 'Comportamiento de Publicación', + }, + details: { + type: 'Tipo', + signature: 'Firma', + group: 'Grupo', + author: 'Autor', + date: 'Fecha', + see: 'Ver', + possibleValues: 'Los valores posibles son', + parameters: 'Parámetros', + throws: 'Lanza', + returnType: 'Tipo de Retorno', + apiName: 'Nombre de API', + required: 'Requerido', + inlineHelpText: 'Texto de Ayuda en Línea', + complianceGroup: 'Grupo de Cumplimiento', + securityClassification: 'Clasificación de Seguridad', + protected: 'Protegido', + }, + typeSuffixes: { + class: 'Clase', + interface: 'Interfaz', + enum: 'Enum', + trigger: 'Disparador', + }, + triggerEvents: { + beforeInsert: 'Antes de Insertar', + beforeUpdate: 'Antes de Actualizar', + beforeDelete: 'Antes de Eliminar', + afterInsert: 'Después de Insertar', + afterUpdate: 'Después de Actualizar', + afterDelete: 'Después de Eliminar', + afterUndelete: 'Después de Recuperar', + }, + publishBehaviors: { + publishImmediately: 'Publicar Inmediatamente', + publishAfterCommit: 'Publicar Después del Commit', + }, + inheritance: { + inheritance: 'Herencia', + implements: 'Implementa', + }, + }, + }; + + const result = mergeTranslations(userTranslations); + + expect(result.changelog.title).toBe('Registro de Cambios'); + expect(result.markdown.sections.methods).toBe('Métodos'); + expect(result.markdown.triggerEvents.beforeInsert).toBe('Antes de Insertar'); + }); + }); + + describe('validateUserTranslations', () => { + it('should return true for undefined', () => { + expect(validateUserTranslations(undefined)).toBe(true); + }); + + it('should return true for null', () => { + expect(validateUserTranslations(null)).toBe(true); + }); + + it('should return true for valid translation object', () => { + const validTranslations = { + changelog: { + title: 'Change History', + }, + markdown: { + sections: { + methods: 'Functions', + }, + }, + }; + + expect(validateUserTranslations(validTranslations)).toBe(true); + }); + + it('should return false for invalid top-level keys', () => { + const invalidTranslations = { + invalidKey: { + title: 'Test', + }, + }; + + const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(); + const result = validateUserTranslations(invalidTranslations); + + expect(result).toBe(false); + expect(consoleSpy).toHaveBeenCalledWith( + 'Invalid translation key: invalidKey. Valid keys are: changelog, markdown' + ); + + consoleSpy.mockRestore(); + }); + + it('should return true for partial valid translations', () => { + const partialTranslations = { + markdown: { + sections: { + methods: 'Functions', + }, + }, + }; + + expect(validateUserTranslations(partialTranslations)).toBe(true); + }); + + it('should return true for string values', () => { + expect(validateUserTranslations('not an object')).toBe(true); + }); + + it('should return true for number values', () => { + expect(validateUserTranslations(123)).toBe(true); + }); + }); +}); diff --git a/src/core/translations/default-translations.ts b/src/core/translations/default-translations.ts new file mode 100644 index 00000000..d513154e --- /dev/null +++ b/src/core/translations/default-translations.ts @@ -0,0 +1,252 @@ +/** + * Default English translations for ApexDocs. + * These can be overridden by users in their configuration. + */ +export type Translations = { + changelog: { + title: string; + newClasses: { + heading: string; + description: string; + }; + newInterfaces: { + heading: string; + description: string; + }; + newEnums: { + heading: string; + description: string; + }; + newCustomObjects: { + heading: string; + description: string; + }; + newTriggers: { + heading: string; + description: string; + }; + removedTypes: { + heading: string; + description: string; + }; + removedCustomObjects: { + heading: string; + description: string; + }; + removedTriggers: { + heading: string; + description: string; + }; + newOrModifiedMembers: { + heading: string; + description: string; + }; + newOrRemovedCustomFields: { + heading: string; + description: string; + }; + newOrRemovedCustomMetadataTypeRecords: { + heading: string; + description: string; + }; + memberModifications: { + newEnumValue: string; + removedEnumValue: string; + newMethod: string; + removedMethod: string; + newProperty: string; + removedProperty: string; + newField: string; + removedField: string; + newType: string; + removedType: string; + newCustomMetadataRecord: string; + removedCustomMetadataRecord: string; + newTrigger: string; + removedTrigger: string; + }; + }; + markdown: { + sections: { + methods: string; + properties: string; + fields: string; + constructors: string; + values: string; // for enums + classes: string; // for inner classes + enums: string; // for inner enums + interfaces: string; // for inner interfaces + namespace: string; + records: string; // for custom metadata records + publishBehavior: string; + }; + // Field/Property/Method details + details: { + type: string; + signature: string; + group: string; + author: string; + date: string; + see: string; + possibleValues: string; // for picklist fields + parameters: string; + throws: string; + returnType: string; + apiName: string; + required: string; + inlineHelpText: string; + complianceGroup: string; + securityClassification: string; + protected: string; + }; + // Class/Interface/Enum suffixes + typeSuffixes: { + class: string; + interface: string; + enum: string; + trigger: string; + }; + // Trigger events + triggerEvents: { + beforeInsert: string; + beforeUpdate: string; + beforeDelete: string; + afterInsert: string; + afterUpdate: string; + afterDelete: string; + afterUndelete: string; + }; + // Publish behaviors + publishBehaviors: { + publishImmediately: string; + publishAfterCommit: string; + }; + // Inheritance and implementation + inheritance: { + inheritance: string; + implements: string; + }; + }; +}; + +export const defaultTranslations: Translations = { + changelog: { + title: 'Changelog', + newClasses: { + heading: 'New Classes', + description: 'These classes are new.', + }, + newInterfaces: { + heading: 'New Interfaces', + description: 'These interfaces are new.', + }, + newEnums: { + heading: 'New Enums', + description: 'These enums are new.', + }, + newCustomObjects: { + heading: 'New Custom Objects', + description: 'These custom objects are new.', + }, + newTriggers: { + heading: 'New Triggers', + description: 'These triggers are new.', + }, + removedTypes: { + heading: 'Removed Types', + description: 'These types have been removed.', + }, + removedCustomObjects: { + heading: 'Removed Custom Objects', + description: 'These custom objects have been removed.', + }, + removedTriggers: { + heading: 'Removed Triggers', + description: 'These triggers have been removed.', + }, + newOrModifiedMembers: { + heading: 'New or Modified Members in Existing Types', + description: 'These members have been added or modified.', + }, + newOrRemovedCustomFields: { + heading: 'New or Removed Fields to Custom Objects or Standard Objects', + description: 'These custom fields have been added or removed.', + }, + newOrRemovedCustomMetadataTypeRecords: { + heading: 'New or Removed Custom Metadata Type Records', + description: 'These custom metadata type records have been added or removed.', + }, + memberModifications: { + newEnumValue: 'New Enum Value', + removedEnumValue: 'Removed Enum Value', + newMethod: 'New Method', + removedMethod: 'Removed Method', + newProperty: 'New Property', + removedProperty: 'Removed Property', + newField: 'New Field', + removedField: 'Removed Field', + newType: 'New Type', + removedType: 'Removed Type', + newCustomMetadataRecord: 'New Custom Metadata Record', + removedCustomMetadataRecord: 'Removed Custom Metadata Record', + newTrigger: 'New Trigger', + removedTrigger: 'Removed Trigger', + }, + }, + markdown: { + sections: { + methods: 'Methods', + properties: 'Properties', + fields: 'Fields', + constructors: 'Constructors', + values: 'Values', + classes: 'Classes', + enums: 'Enums', + interfaces: 'Interfaces', + namespace: 'Namespace', + records: 'Records', + publishBehavior: 'Publish Behavior', + }, + details: { + type: 'Type', + signature: 'Signature', + group: 'Group', + author: 'Author', + date: 'Date', + see: 'See', + possibleValues: 'Possible values are', + parameters: 'Parameters', + throws: 'Throws', + returnType: 'Return Type', + apiName: 'API Name', + required: 'Required', + inlineHelpText: 'Inline Help Text', + complianceGroup: 'Compliance Group', + securityClassification: 'Security Classification', + protected: 'Protected', + }, + typeSuffixes: { + class: 'Class', + interface: 'Interface', + enum: 'Enum', + trigger: 'Trigger', + }, + triggerEvents: { + beforeInsert: 'Before Insert', + beforeUpdate: 'Before Update', + beforeDelete: 'Before Delete', + afterInsert: 'After Insert', + afterUpdate: 'After Update', + afterDelete: 'After Delete', + afterUndelete: 'After Undelete', + }, + publishBehaviors: { + publishImmediately: 'Publish Immediately', + publishAfterCommit: 'Publish After Commit', + }, + inheritance: { + inheritance: 'Inheritance', + implements: 'Implements', + }, + }, +}; diff --git a/src/core/translations/index.ts b/src/core/translations/index.ts new file mode 100644 index 00000000..45eb3a80 --- /dev/null +++ b/src/core/translations/index.ts @@ -0,0 +1,2 @@ +export { defaultTranslations, type Translations } from './default-translations'; +export { mergeTranslations, validateUserTranslations, type UserTranslations } from './translation-utils'; diff --git a/src/core/translations/translation-utils.ts b/src/core/translations/translation-utils.ts new file mode 100644 index 00000000..286f139e --- /dev/null +++ b/src/core/translations/translation-utils.ts @@ -0,0 +1,109 @@ +import { Translations, defaultTranslations } from './default-translations'; + +/** + * User-provided partial translations that can override the defaults. + */ +export type UserTranslations = DeepPartial; + +/** + * Utility type to make all properties in T optional recursively. + */ +type DeepPartial = { + [P in keyof T]?: T[P] extends object ? DeepPartial : T[P]; +}; + +/** + * Type representing any object with string keys and unknown values. + */ +type ObjectWithStringKeys = Record; + +/** + * Merges user-provided translations with the default translations. + * User translations take precedence over defaults. + * + * @param userTranslations - Optional user-provided translations + * @returns Complete translations object with user overrides applied + */ +export function mergeTranslations(userTranslations?: UserTranslations): Translations { + if (!userTranslations) { + return defaultTranslations; + } + + return JSON.parse( + JSON.stringify(Object.assign({}, defaultTranslations, deepMerge(defaultTranslations, userTranslations))), + ) as Translations; +} + +/** + * Type guard to check if a value is a plain object. + */ +function isObjectWithStringKeys(value: unknown): value is ObjectWithStringKeys { + return value !== null && typeof value === 'object' && !Array.isArray(value); +} + +/** + * Deep merges two objects, with the second object taking precedence. + * Both objects must have string keys and unknown values. + * + * @param target - The target object (defaults) + * @param source - The source object (user overrides) + * @returns Merged object + */ +function deepMerge(target: T, source: U): T & U { + const result = { ...target } as T & U; + + for (const key in source) { + if (Object.prototype.hasOwnProperty.call(source, key)) { + const sourceValue = source[key]; + const targetValue = result[key as keyof T]; + + if (isObjectWithStringKeys(sourceValue) && isObjectWithStringKeys(targetValue)) { + result[key as keyof (T & U)] = deepMerge(targetValue, sourceValue) as (T & U)[keyof (T & U)]; + } else if (sourceValue !== undefined) { + result[key as keyof (T & U)] = sourceValue as (T & U)[keyof (T & U)]; + } + } + } + + return result; +} + +/** + * Checks if a value is a plain object (not an array or null). + * + * @param value - The value to check + * @returns True if the value is a plain object + */ +function isObject(value: unknown): value is Record { + return value !== null && typeof value === 'object' && !Array.isArray(value); +} + +/** + * Validates that user translations follow the expected structure. + * This is a basic validation to catch common mistakes. + * + * @param userTranslations - User-provided translations + * @returns True if valid, false otherwise + */ +export function validateUserTranslations(userTranslations: unknown): userTranslations is UserTranslations { + if (!userTranslations || typeof userTranslations !== 'object') { + return true; // undefined or null is valid (no overrides) + } + + if (!isObject(userTranslations)) { + return false; + } + + // Basic validation - check that top-level keys are valid + const validTopLevelKeys: Array = ['changelog', 'markdown']; + const userKeys = Object.keys(userTranslations); + + for (const key of userKeys) { + if (!validTopLevelKeys.includes(key as keyof Translations)) { + console.warn(`Invalid translation key: ${key}. Valid keys are: ${validTopLevelKeys.join(', ')}`); + return false; + } + } + + return true; +} diff --git a/src/index.ts b/src/index.ts index 1afe5ecc..afec8304 100644 --- a/src/index.ts +++ b/src/index.ts @@ -20,6 +20,7 @@ import type { ChangelogConfigurableHooks, TransformChangelogPage, } from './core/shared/types'; +import type { Translations, UserTranslations } from './core/translations'; import { skip } from './core/shared/utils'; import { changeLogDefaults, markdownDefaults, openApiDefaults } from './defaults'; import { process } from './node/process'; @@ -92,4 +93,6 @@ export { process, ChangelogConfigurableHooks, TransformChangelogPage, + Translations, + UserTranslations, }; From 531c9a0d335d32673ee943cc9b535f29c32da7a4 Mon Sep 17 00:00:00 2001 From: cesarParra Date: Sun, 29 Jun 2025 09:25:02 -0400 Subject: [PATCH 2/6] Add Spanish translations and example metadata for documentation generation --- README.md | 110 +++ .../translation-example/apexdocs.config.js | 130 ---- examples/translation/.forceignore | 12 + examples/translation/apexdocs.config.ts | 43 ++ .../config/project-scratch-def.json | 5 + .../docs/custom-objects/Account.md | 4 + .../docs/custom-objects/Contact.md | 15 + .../docs/custom-objects/Event__c.md | 77 ++ .../docs/custom-objects/Price_Component__c.md | 71 ++ .../Product_Price_Component__c.md | 26 + .../docs/custom-objects/Product__c.md | 40 + .../custom-objects/Sales_Order_Line__c.md | 68 ++ .../docs/custom-objects/Sales_Order__c.md | 6 + .../docs/custom-objects/Speaker__c.md | 39 + examples/translation/docs/index.md | 69 ++ .../docs/miscellaneous/BaseClass.md | 13 + .../miscellaneous/MultiInheritanceClass.md | 69 ++ .../docs/miscellaneous/ParentInterface.md | 12 + .../docs/miscellaneous/ReferencedEnum.md | 8 + .../docs/miscellaneous/SampleException.md | 21 + .../docs/miscellaneous/SampleInterface.md | 109 +++ .../translation/docs/miscellaneous/Url.md | 310 ++++++++ .../docs/sample-enums/SampleEnum.md | 33 + .../docs/samplegroup/SampleClass.md | 159 ++++ .../force-app/classes/BaseClass.cls | 3 + .../force-app/classes/BaseClass.cls-meta.xml | 5 + .../classes/MultiInheritanceClass.cls | 1 + .../MultiInheritanceClass.cls-meta.xml | 5 + .../force-app/classes/ParentInterface.cls | 3 + .../classes/ParentInterface.cls-meta.xml | 5 + .../force-app/classes/ReferencedEnum.cls | 5 + .../classes/ReferencedEnum.cls-meta.xml | 5 + .../translation/force-app/classes/Url.cls | 198 +++++ .../force-app/classes/Url.cls-meta.xml | 5 + .../classes/feature-a/SampleClass.cls | 74 ++ .../feature-a/SampleClass.cls-meta.xml | 5 + .../classes/feature-a/SampleEnum.cls | 30 + .../classes/feature-a/SampleEnum.cls-meta.xml | 5 + .../classes/feature-a/SampleException.cls | 17 + .../feature-a/SampleException.cls-meta.xml | 5 + .../classes/feature-a/SampleInterface.cls | 46 ++ .../feature-a/SampleInterface.cls-meta.xml | 5 + .../objects/Account/Account.object-meta.xml | 90 +++ .../objects/Contact/Contact.object-meta.xml | 3 + .../Contact/fields/PhotoUrl__c.field-meta.xml | 9 + .../objects/Event__c/Event__c.object-meta.xml | 167 ++++ .../fields/Description__c.field-meta.xml | 10 + .../fields/End_Date__c.field-meta.xml | 9 + .../fields/Location__c.field-meta.xml | 11 + .../Social_Security_Number__c.field-meta.xml | 13 + .../fields/Start_Date__c.field-meta.xml | 9 + .../fields/Tag_Line__c.field-meta.xml | 11 + .../Price_Component__c.object-meta.xml | 169 ++++ .../fields/Description__c.field-meta.xml | 11 + .../fields/Expression__c.field-meta.xml | 12 + .../fields/Percent__c.field-meta.xml | 13 + .../fields/Price__c.field-meta.xml | 13 + .../fields/Type__c.field-meta.xml | 30 + ...Product_Price_Component__c.object-meta.xml | 166 ++++ .../fields/Price_Component__c.field-meta.xml | 14 + .../fields/Product__c.field-meta.xml | 14 + .../Product__c/Product__c.object-meta.xml | 169 ++++ .../fields/Description__c.field-meta.xml | 11 + .../Product__c/fields/Event__c.field-meta.xml | 12 + .../fields/Features__c.field-meta.xml | 10 + .../Sales_Order_Line__c.object-meta.xml | 167 ++++ .../fields/Amount__c.field-meta.xml | 11 + .../fields/Product__c.field-meta.xml | 13 + .../fields/Sales_Order__c.field-meta.xml | 14 + .../Source_Price_Component__c.field-meta.xml | 13 + .../fields/Type__c.field-meta.xml | 26 + .../Sales_Order__c.object-meta.xml | 170 ++++ .../Speaker__c/Speaker__c.object-meta.xml | 167 ++++ .../Speaker__c/fields/About__c.field-meta.xml | 10 + .../Speaker__c/fields/Event__c.field-meta.xml | 14 + .../fields/Person__c.field-meta.xml | 14 + examples/translation/package-lock.json | 724 ++++++++++++++++++ examples/translation/package.json | 15 + examples/translation/sfdx-project.json | 12 + .../adapters/renderable-to-page-data.ts | 2 +- src/core/markdown/templates/class-template.ts | 4 +- .../templates/custom-object-template.ts | 20 +- .../markdown/templates/type-doc-partial.ts | 12 +- 83 files changed, 4107 insertions(+), 148 deletions(-) delete mode 100644 examples/translation-example/apexdocs.config.js create mode 100755 examples/translation/.forceignore create mode 100644 examples/translation/apexdocs.config.ts create mode 100644 examples/translation/config/project-scratch-def.json create mode 100644 examples/translation/docs/custom-objects/Account.md create mode 100644 examples/translation/docs/custom-objects/Contact.md create mode 100644 examples/translation/docs/custom-objects/Event__c.md create mode 100644 examples/translation/docs/custom-objects/Price_Component__c.md create mode 100644 examples/translation/docs/custom-objects/Product_Price_Component__c.md create mode 100644 examples/translation/docs/custom-objects/Product__c.md create mode 100644 examples/translation/docs/custom-objects/Sales_Order_Line__c.md create mode 100644 examples/translation/docs/custom-objects/Sales_Order__c.md create mode 100644 examples/translation/docs/custom-objects/Speaker__c.md create mode 100644 examples/translation/docs/index.md create mode 100644 examples/translation/docs/miscellaneous/BaseClass.md create mode 100644 examples/translation/docs/miscellaneous/MultiInheritanceClass.md create mode 100644 examples/translation/docs/miscellaneous/ParentInterface.md create mode 100644 examples/translation/docs/miscellaneous/ReferencedEnum.md create mode 100644 examples/translation/docs/miscellaneous/SampleException.md create mode 100644 examples/translation/docs/miscellaneous/SampleInterface.md create mode 100644 examples/translation/docs/miscellaneous/Url.md create mode 100644 examples/translation/docs/sample-enums/SampleEnum.md create mode 100644 examples/translation/docs/samplegroup/SampleClass.md create mode 100644 examples/translation/force-app/classes/BaseClass.cls create mode 100644 examples/translation/force-app/classes/BaseClass.cls-meta.xml create mode 100644 examples/translation/force-app/classes/MultiInheritanceClass.cls create mode 100644 examples/translation/force-app/classes/MultiInheritanceClass.cls-meta.xml create mode 100644 examples/translation/force-app/classes/ParentInterface.cls create mode 100644 examples/translation/force-app/classes/ParentInterface.cls-meta.xml create mode 100644 examples/translation/force-app/classes/ReferencedEnum.cls create mode 100644 examples/translation/force-app/classes/ReferencedEnum.cls-meta.xml create mode 100644 examples/translation/force-app/classes/Url.cls create mode 100644 examples/translation/force-app/classes/Url.cls-meta.xml create mode 100644 examples/translation/force-app/classes/feature-a/SampleClass.cls create mode 100644 examples/translation/force-app/classes/feature-a/SampleClass.cls-meta.xml create mode 100644 examples/translation/force-app/classes/feature-a/SampleEnum.cls create mode 100644 examples/translation/force-app/classes/feature-a/SampleEnum.cls-meta.xml create mode 100644 examples/translation/force-app/classes/feature-a/SampleException.cls create mode 100644 examples/translation/force-app/classes/feature-a/SampleException.cls-meta.xml create mode 100644 examples/translation/force-app/classes/feature-a/SampleInterface.cls create mode 100644 examples/translation/force-app/classes/feature-a/SampleInterface.cls-meta.xml create mode 100644 examples/translation/force-app/objects/Account/Account.object-meta.xml create mode 100644 examples/translation/force-app/objects/Contact/Contact.object-meta.xml create mode 100644 examples/translation/force-app/objects/Contact/fields/PhotoUrl__c.field-meta.xml create mode 100644 examples/translation/force-app/objects/Event__c/Event__c.object-meta.xml create mode 100644 examples/translation/force-app/objects/Event__c/fields/Description__c.field-meta.xml create mode 100644 examples/translation/force-app/objects/Event__c/fields/End_Date__c.field-meta.xml create mode 100644 examples/translation/force-app/objects/Event__c/fields/Location__c.field-meta.xml create mode 100644 examples/translation/force-app/objects/Event__c/fields/Social_Security_Number__c.field-meta.xml create mode 100644 examples/translation/force-app/objects/Event__c/fields/Start_Date__c.field-meta.xml create mode 100644 examples/translation/force-app/objects/Event__c/fields/Tag_Line__c.field-meta.xml create mode 100644 examples/translation/force-app/objects/Price_Component__c/Price_Component__c.object-meta.xml create mode 100644 examples/translation/force-app/objects/Price_Component__c/fields/Description__c.field-meta.xml create mode 100644 examples/translation/force-app/objects/Price_Component__c/fields/Expression__c.field-meta.xml create mode 100644 examples/translation/force-app/objects/Price_Component__c/fields/Percent__c.field-meta.xml create mode 100644 examples/translation/force-app/objects/Price_Component__c/fields/Price__c.field-meta.xml create mode 100644 examples/translation/force-app/objects/Price_Component__c/fields/Type__c.field-meta.xml create mode 100644 examples/translation/force-app/objects/Product_Price_Component__c/Product_Price_Component__c.object-meta.xml create mode 100644 examples/translation/force-app/objects/Product_Price_Component__c/fields/Price_Component__c.field-meta.xml create mode 100644 examples/translation/force-app/objects/Product_Price_Component__c/fields/Product__c.field-meta.xml create mode 100644 examples/translation/force-app/objects/Product__c/Product__c.object-meta.xml create mode 100644 examples/translation/force-app/objects/Product__c/fields/Description__c.field-meta.xml create mode 100644 examples/translation/force-app/objects/Product__c/fields/Event__c.field-meta.xml create mode 100644 examples/translation/force-app/objects/Product__c/fields/Features__c.field-meta.xml create mode 100644 examples/translation/force-app/objects/Sales_Order_Line__c/Sales_Order_Line__c.object-meta.xml create mode 100644 examples/translation/force-app/objects/Sales_Order_Line__c/fields/Amount__c.field-meta.xml create mode 100644 examples/translation/force-app/objects/Sales_Order_Line__c/fields/Product__c.field-meta.xml create mode 100644 examples/translation/force-app/objects/Sales_Order_Line__c/fields/Sales_Order__c.field-meta.xml create mode 100644 examples/translation/force-app/objects/Sales_Order_Line__c/fields/Source_Price_Component__c.field-meta.xml create mode 100644 examples/translation/force-app/objects/Sales_Order_Line__c/fields/Type__c.field-meta.xml create mode 100644 examples/translation/force-app/objects/Sales_Order__c/Sales_Order__c.object-meta.xml create mode 100644 examples/translation/force-app/objects/Speaker__c/Speaker__c.object-meta.xml create mode 100644 examples/translation/force-app/objects/Speaker__c/fields/About__c.field-meta.xml create mode 100644 examples/translation/force-app/objects/Speaker__c/fields/Event__c.field-meta.xml create mode 100644 examples/translation/force-app/objects/Speaker__c/fields/Person__c.field-meta.xml create mode 100644 examples/translation/package-lock.json create mode 100644 examples/translation/package.json create mode 100644 examples/translation/sfdx-project.json diff --git a/README.md b/README.md index 75658366..ae5b3d89 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,26 @@ ApexDocs is a non-opinionated documentation generator for Salesforce Apex classe It can output documentation in Markdown format, which allows you to use the Static Site Generator of your choice to create a documentation site that fits your needs, hosted in any static web hosting service. +## Table of Contents + +- [👀 Examples](#-examples) +- [🚀 Features](#-features) +- [💿 Installation](#-installation) +- [⚡ Quick Start](#-quick-start) + - [CLI](#cli) + - [Markdown](#markdown) + - [OpenApi](#openapi) + - [Changelog](#changelog) +- [▶️ Available Commands](#️-available-commands) + - [Markdown](#markdown-1) + - [OpenApi](#openapi-1) + - [Changelog](#changelog-1) +- [🔬 Defining a configuration file](#-defining-a-configuration-file) +- [🌐 Translation](#-translation-support) +- [⤵︎ Importing to your project](#︎-importing-to-your-project) +- [📖 Documentation Guide](#-documentation-guide) +- [📄 Generating OpenApi REST Definitions](#-generating-openapi-rest-definitions) + ## 👀 Examples ApexDocs generates Markdown files, which can be integrated into any Static Site Generation (SSG) engine, @@ -64,6 +84,7 @@ Here are some live projects using ApexDocs: * Support for ignoring files and members from being documented * Namespace support * Configuration file support +* Translation support for different languages and custom terminology * Single line ApexDoc Blocks * Custom tag support * And much, much more! @@ -274,6 +295,14 @@ export default defineMarkdownConfig({ sourceDir: 'force-app', targetDir: 'docs', scope: ['global', 'public'], + translations: { + markdown: { + sections: { + methods: 'Methods', + properties: 'Properties', + }, + }, + }, ... }); ``` @@ -595,6 +624,87 @@ export default { }; ``` +## 🌐 Translation + +ApexDocs supports translations to customize the language and terminology used in the generated documentation. +This feature allows you to: + +- **Translate documentation to different languages** (Spanish, French, etc.) +- **Use custom business terminology** (e.g., "Business Operations" instead of "Methods") +- **Partially override specific terms** while keeping the rest in English + +Translation is supported for the `markdown` and `changelog` generators. + +### How It Works + +The translation system uses: + +- **Default English translations** built into the system +- **User-provided overrides** that can be partial or complete + +### Configuration + +Add a `translations` property to your ApexDocs configuration (JS or TS file): + +```javascript +import { defineMarkdownConfig } from '@cparra/apexdocs'; + +export default defineMarkdownConfig({ + sourceDir: 'src', + targetDir: 'docs', + scope: ['public', 'global'], + translations: { + markdown: { + sections: { + methods: 'Métodos', + properties: 'Propiedades', + fields: 'Campos', + }, + }, + }, +}); +``` + +### TypeScript Support + +For TypeScript projects, import the translation types for better autocomplete and type safety: + +```typescript +import { defineMarkdownConfig } from '@cparra/apexdocs'; +import type { UserTranslations } from '@cparra/apexdocs'; + +const translations: UserTranslations = { + markdown: { + sections: { + methods: 'Functions', + }, + }, +}; + +export default defineMarkdownConfig({ + sourceDir: 'src', + targetDir: 'docs', + scope: ['public', 'global'], + translations, +}); +``` + +### Best Practices + +1. **Start Small**: Begin with partial translations for the most important terms +2. **Be Consistent**: Use the same terminology across your organization +3. **Test Thoroughly**: Generate documentation with your translations to verify the output +4. **Version Control**: Include your translation configurations in version control + +### Notes + +- Only the **markdown** and **changelog** generators support translations +- The **OpenAPI** generator does not use the translation system +- All translations are optional - anything not specified uses the English default +- The system uses deep merging, so partial translations work seamlessly + +For a complete example, see the [translation example](examples/translation/) in this repository. + ## ⤵︎ Importing to your project ### Reflection diff --git a/examples/translation-example/apexdocs.config.js b/examples/translation-example/apexdocs.config.js deleted file mode 100644 index 99d90d8d..00000000 --- a/examples/translation-example/apexdocs.config.js +++ /dev/null @@ -1,130 +0,0 @@ -import { defineMarkdownConfig, defineChangelogConfig } from '../../src/index.js'; - -// Example of using custom translations in different languages - -// Spanish translations example -const spanishTranslations = { - changelog: { - title: 'Registro de Cambios', - newClasses: { - heading: 'Nuevas Clases', - description: 'Estas clases son nuevas.', - }, - newInterfaces: { - heading: 'Nuevas Interfaces', - description: 'Estas interfaces son nuevas.', - }, - newEnums: { - heading: 'Nuevos Enums', - description: 'Estos enums son nuevos.', - }, - removedTypes: { - heading: 'Tipos Eliminados', - description: 'Estos tipos han sido eliminados.', - }, - memberModifications: { - newMethod: 'Nuevo Método', - removedMethod: 'Método Eliminado', - newProperty: 'Nueva Propiedad', - removedProperty: 'Propiedad Eliminada', - }, - }, - markdown: { - sections: { - methods: 'Métodos', - properties: 'Propiedades', - fields: 'Campos', - constructors: 'Constructores', - namespace: 'Espacio de Nombres', - }, - details: { - type: 'Tipo', - signature: 'Firma', - parameters: 'Parámetros', - returnType: 'Tipo de Retorno', - throws: 'Lanza', - }, - typeSuffixes: { - class: 'Clase', - interface: 'Interfaz', - enum: 'Enum', - trigger: 'Disparador', - }, - }, -}; - -// Custom business terminology example (English but with different terms) -const businessTerminology = { - markdown: { - sections: { - methods: 'Business Operations', - properties: 'Business Attributes', - fields: 'Data Elements', - constructors: 'Initializers', - }, - details: { - parameters: 'Input Parameters', - returnType: 'Output Type', - }, - typeSuffixes: { - class: 'Service', - interface: 'Contract', - }, - }, -}; - -// Partial translations example - only override specific terms -const partialTranslations = { - changelog: { - title: 'Change History', // Only override the title - }, - markdown: { - sections: { - methods: 'Functions', // Use "Functions" instead of "Methods" - }, - }, -}; - -export default { - // Example 1: Spanish documentation - spanish: defineMarkdownConfig({ - sourceDir: 'src', - targetDir: 'docs-es', - scope: ['public', 'global'], - translations: spanishTranslations, - }), - - // Example 2: Custom business terminology - business: defineMarkdownConfig({ - sourceDir: 'src', - targetDir: 'docs-business', - scope: ['public', 'global'], - translations: businessTerminology, - }), - - // Example 3: Partial translations (most text remains in English) - partial: defineMarkdownConfig({ - sourceDir: 'src', - targetDir: 'docs-partial', - scope: ['public', 'global'], - translations: partialTranslations, - }), - - // Example 4: Changelog with Spanish translations - changelogSpanish: defineChangelogConfig({ - previousVersionDir: 'previous', - currentVersionDir: 'current', - targetDir: 'changelog-es', - fileName: 'CAMBIOS', - scope: ['public', 'global'], - translations: spanishTranslations, - }), - - // Example 5: No translations (uses defaults) - default: defineMarkdownConfig({ - sourceDir: 'src', - targetDir: 'docs-default', - scope: ['public', 'global'], - // No translations property - will use English defaults - }), -}; diff --git a/examples/translation/.forceignore b/examples/translation/.forceignore new file mode 100755 index 00000000..7b5b5a71 --- /dev/null +++ b/examples/translation/.forceignore @@ -0,0 +1,12 @@ +# List files or directories below to ignore them when running force:source:push, force:source:pull, and force:source:status +# More information: https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_exclude_source.htm +# + +package.xml + +# LWC configuration files +**/jsconfig.json +**/.eslintrc.json + +# LWC Jest +**/__tests__/** \ No newline at end of file diff --git a/examples/translation/apexdocs.config.ts b/examples/translation/apexdocs.config.ts new file mode 100644 index 00000000..bb79d2ec --- /dev/null +++ b/examples/translation/apexdocs.config.ts @@ -0,0 +1,43 @@ +import { defineMarkdownConfig, UserTranslations } from '../../src'; + +// Spanish translations +const spanishTranslations: UserTranslations = { + markdown: { + sections: { + methods: 'Métodos', + properties: 'Propiedades', + fields: 'Campos', + constructors: 'Constructores', + namespace: 'Espacio de Nombres', + values: 'Valores', + }, + details: { + apiName: 'Nombre API', + type: 'Tipo', + signature: 'Firma', + parameters: 'Parámetros', + returnType: 'Tipo de Retorno', + throws: 'Lanza', + required: 'Requerido', + author: 'Autor', + }, + typeSuffixes: { + class: 'Clase', + interface: 'Interfaz', + enum: 'Enum', + trigger: 'Disparador', + }, + inheritance: { + inheritance: 'Herencia', + implements: 'Implementa', + }, + }, +}; + +export default { + markdown: defineMarkdownConfig({ + sourceDir: 'force-app', + scope: ['global', 'public'], + translations: spanishTranslations, + }), +}; diff --git a/examples/translation/config/project-scratch-def.json b/examples/translation/config/project-scratch-def.json new file mode 100644 index 00000000..02b9f9f1 --- /dev/null +++ b/examples/translation/config/project-scratch-def.json @@ -0,0 +1,5 @@ +{ + "orgName": "cesarparra company", + "edition": "Developer", + "features": [] +} diff --git a/examples/translation/docs/custom-objects/Account.md b/examples/translation/docs/custom-objects/Account.md new file mode 100644 index 00000000..fe7e2b46 --- /dev/null +++ b/examples/translation/docs/custom-objects/Account.md @@ -0,0 +1,4 @@ +# Account + +## Nombre API +`Account` \ No newline at end of file diff --git a/examples/translation/docs/custom-objects/Contact.md b/examples/translation/docs/custom-objects/Contact.md new file mode 100644 index 00000000..10c3b872 --- /dev/null +++ b/examples/translation/docs/custom-objects/Contact.md @@ -0,0 +1,15 @@ +# Contact + +## Nombre API +`Contact` + +## Campos +### PhotoUrl + +**Nombre API** + +`PhotoUrl__c` + +**Tipo** + +*Url* \ No newline at end of file diff --git a/examples/translation/docs/custom-objects/Event__c.md b/examples/translation/docs/custom-objects/Event__c.md new file mode 100644 index 00000000..91a34846 --- /dev/null +++ b/examples/translation/docs/custom-objects/Event__c.md @@ -0,0 +1,77 @@ +# Event + +Represents an event that people can register for. + +## Nombre API +`Event__c` + +## Campos +### Description + +**Nombre API** + +`Description__c` + +**Tipo** + +*LongTextArea* + +--- +### End Date +**Requerido** + +**Nombre API** + +`End_Date__c` + +**Tipo** + +*Date* + +--- +### Location +**Requerido** + +**Nombre API** + +`Location__c` + +**Tipo** + +*Location* + +--- +### Social Security Number + +Used to store the U.S. social security number in 9 digit format. + +**Nombre API** + +`Social_Security_Number__c` + +**Tipo** + +*Text* + +--- +### Start Date +**Requerido** + +**Nombre API** + +`Start_Date__c` + +**Tipo** + +*Date* + +--- +### Tag Line + +**Nombre API** + +`Tag_Line__c` + +**Tipo** + +*Text* \ No newline at end of file diff --git a/examples/translation/docs/custom-objects/Price_Component__c.md b/examples/translation/docs/custom-objects/Price_Component__c.md new file mode 100644 index 00000000..641ace24 --- /dev/null +++ b/examples/translation/docs/custom-objects/Price_Component__c.md @@ -0,0 +1,71 @@ +# Price Component + +## Nombre API +`Price_Component__c` + +## Campos +### Description + +**Nombre API** + +`Description__c` + +**Tipo** + +*Text* + +--- +### Expression + +The Expression that determines if this price should take effect or not. + +**Nombre API** + +`Expression__c` + +**Tipo** + +*LongTextArea* + +--- +### Percent + +Use this field to calculate the price based on the list price's percentage instead of providing a flat price. + +**Nombre API** + +`Percent__c` + +**Tipo** + +*Percent* + +--- +### Price + +Use this when the Price Component represents a Flat Price. To represent a Percentage use the Percent field. + +**Nombre API** + +`Price__c` + +**Tipo** + +*Currency* + +--- +### Type +**Requerido** + +**Nombre API** + +`Type__c` + +**Tipo** + +*Picklist* + +#### Possible values are +* List Price +* Surcharge +* Discount \ No newline at end of file diff --git a/examples/translation/docs/custom-objects/Product_Price_Component__c.md b/examples/translation/docs/custom-objects/Product_Price_Component__c.md new file mode 100644 index 00000000..c077715a --- /dev/null +++ b/examples/translation/docs/custom-objects/Product_Price_Component__c.md @@ -0,0 +1,26 @@ +# Product Price Component + +## Nombre API +`Product_Price_Component__c` + +## Campos +### Price Component + +**Nombre API** + +`Price_Component__c` + +**Tipo** + +*MasterDetail* + +--- +### Product + +**Nombre API** + +`Product__c` + +**Tipo** + +*MasterDetail* \ No newline at end of file diff --git a/examples/translation/docs/custom-objects/Product__c.md b/examples/translation/docs/custom-objects/Product__c.md new file mode 100644 index 00000000..ca9bd78e --- /dev/null +++ b/examples/translation/docs/custom-objects/Product__c.md @@ -0,0 +1,40 @@ +# Product (Custom) + +Product that is sold or available for sale. + +## Nombre API +`Product__c` + +## Campos +### Description + +**Nombre API** + +`Description__c` + +**Tipo** + +*Text* + +--- +### Event +**Requerido** + +**Nombre API** + +`Event__c` + +**Tipo** + +*Lookup* + +--- +### Features + +**Nombre API** + +`Features__c` + +**Tipo** + +*LongTextArea* \ No newline at end of file diff --git a/examples/translation/docs/custom-objects/Sales_Order_Line__c.md b/examples/translation/docs/custom-objects/Sales_Order_Line__c.md new file mode 100644 index 00000000..8ec4a896 --- /dev/null +++ b/examples/translation/docs/custom-objects/Sales_Order_Line__c.md @@ -0,0 +1,68 @@ +# Sales Order Line + +Represents a line item on a sales order. + +## Nombre API +`Sales_Order_Line__c` + +## Campos +### Amount +**Requerido** + +**Nombre API** + +`Amount__c` + +**Tipo** + +*Currency* + +--- +### Product +**Requerido** + +**Nombre API** + +`Product__c` + +**Tipo** + +*Lookup* + +--- +### Sales Order + +**Nombre API** + +`Sales_Order__c` + +**Tipo** + +*MasterDetail* + +--- +### Source Price Component + +**Nombre API** + +`Source_Price_Component__c` + +**Tipo** + +*Lookup* + +--- +### Type +**Requerido** + +**Nombre API** + +`Type__c` + +**Tipo** + +*Picklist* + +#### Possible values are +* Charge +* Discount \ No newline at end of file diff --git a/examples/translation/docs/custom-objects/Sales_Order__c.md b/examples/translation/docs/custom-objects/Sales_Order__c.md new file mode 100644 index 00000000..daa35cb2 --- /dev/null +++ b/examples/translation/docs/custom-objects/Sales_Order__c.md @@ -0,0 +1,6 @@ +# Sales Order + +Custom object for tracking sales orders. + +## Nombre API +`Sales_Order__c` \ No newline at end of file diff --git a/examples/translation/docs/custom-objects/Speaker__c.md b/examples/translation/docs/custom-objects/Speaker__c.md new file mode 100644 index 00000000..dff3f6ab --- /dev/null +++ b/examples/translation/docs/custom-objects/Speaker__c.md @@ -0,0 +1,39 @@ +# Speaker + +Represents a speaker at an event. + +## Nombre API +`Speaker__c` + +## Campos +### About + +**Nombre API** + +`About__c` + +**Tipo** + +*LongTextArea* + +--- +### Event + +**Nombre API** + +`Event__c` + +**Tipo** + +*MasterDetail* + +--- +### Person + +**Nombre API** + +`Person__c` + +**Tipo** + +*MasterDetail* \ No newline at end of file diff --git a/examples/translation/docs/index.md b/examples/translation/docs/index.md new file mode 100644 index 00000000..71d689be --- /dev/null +++ b/examples/translation/docs/index.md @@ -0,0 +1,69 @@ +# Reference Guide + +## Custom Objects + +### [Account](custom-objects/Account.md) + +### [Contact](custom-objects/Contact.md) + +### [Event__c](custom-objects/Event__c.md) + +Represents an event that people can register for. + +### [Price_Component__c](custom-objects/Price_Component__c.md) + +### [Product_Price_Component__c](custom-objects/Product_Price_Component__c.md) + +### [Product__c](custom-objects/Product__c.md) + +Product that is sold or available for sale. + +### [Sales_Order_Line__c](custom-objects/Sales_Order_Line__c.md) + +Represents a line item on a sales order. + +### [Sales_Order__c](custom-objects/Sales_Order__c.md) + +Custom object for tracking sales orders. + +### [Speaker__c](custom-objects/Speaker__c.md) + +Represents a speaker at an event. + +## Miscellaneous + +### [BaseClass](miscellaneous/BaseClass.md) + +### [MultiInheritanceClass](miscellaneous/MultiInheritanceClass.md) + +### [ParentInterface](miscellaneous/ParentInterface.md) + +### [ReferencedEnum](miscellaneous/ReferencedEnum.md) + +### [Url](miscellaneous/Url.md) + +Represents a uniform resource locator (URL) and provides access to parts of the URL. +Enables access to the base URL used to access your Salesforce org. + +### [SampleException](miscellaneous/SampleException.md) + +This is a sample exception. + +### [SampleInterface](miscellaneous/SampleInterface.md) + +This is a sample interface + +## Sample Enums + +### [SampleEnum](sample-enums/SampleEnum.md) + +This is a sample enum. This references [ReferencedEnum](miscellaneous/ReferencedEnum.md) . + +This description has several lines + +## SampleGroup + +### [SampleClass](samplegroup/SampleClass.md) + +aliquip ex sunt officia ullamco anim deserunt magna aliquip nisi eiusmod in sit officia veniam ex +**deserunt** ea officia exercitation laboris enim in duis quis enim eiusmod eu amet cupidatat. \ No newline at end of file diff --git a/examples/translation/docs/miscellaneous/BaseClass.md b/examples/translation/docs/miscellaneous/BaseClass.md new file mode 100644 index 00000000..eb5a23b7 --- /dev/null +++ b/examples/translation/docs/miscellaneous/BaseClass.md @@ -0,0 +1,13 @@ +# BaseClass Clase +`abstract` + +## Campos +### `sampleEnumFromBase` + +#### Firma +```apex +public sampleEnumFromBase +``` + +#### Tipo +[SampleEnum](../sample-enums/SampleEnum.md) \ No newline at end of file diff --git a/examples/translation/docs/miscellaneous/MultiInheritanceClass.md b/examples/translation/docs/miscellaneous/MultiInheritanceClass.md new file mode 100644 index 00000000..0099d652 --- /dev/null +++ b/examples/translation/docs/miscellaneous/MultiInheritanceClass.md @@ -0,0 +1,69 @@ +# MultiInheritanceClass Clase + +**Herencia** + +[SampleClass](../samplegroup/SampleClass.md) < [BaseClass](BaseClass.md) + +## Campos +### `sampleEnumFromBase` + +*Inherited* + +#### Firma +```apex +public sampleEnumFromBase +``` + +#### Tipo +[SampleEnum](../sample-enums/SampleEnum.md) + +## Propiedades +### Group Name +#### `someProperty` + +*Inherited* + +##### Firma +```apex +public someProperty +``` + +##### Tipo +String + +## Métodos +### Available Methods +#### `doSomething()` + +*Inherited* + +##### Firma +```apex +public void doSomething() +``` + +##### Tipo de Retorno +**void** + +### Deprecated Methods +#### `sayHello()` + +*Inherited* + +`DEPRECATED` + +This is a sample method. + +##### Firma +```apex +public virtual String sayHello() +``` + +##### Tipo de Retorno +**String** + +A string value. + +##### Example +SampleClass sample = new SampleClass(); +sample.doSomething(); \ No newline at end of file diff --git a/examples/translation/docs/miscellaneous/ParentInterface.md b/examples/translation/docs/miscellaneous/ParentInterface.md new file mode 100644 index 00000000..5d47bb7c --- /dev/null +++ b/examples/translation/docs/miscellaneous/ParentInterface.md @@ -0,0 +1,12 @@ +# ParentInterface Interfaz + +## Métodos +### `sampleParentMethod()` + +#### Firma +```apex +public void sampleParentMethod() +``` + +#### Tipo de Retorno +**void** \ No newline at end of file diff --git a/examples/translation/docs/miscellaneous/ReferencedEnum.md b/examples/translation/docs/miscellaneous/ReferencedEnum.md new file mode 100644 index 00000000..af2d6a49 --- /dev/null +++ b/examples/translation/docs/miscellaneous/ReferencedEnum.md @@ -0,0 +1,8 @@ +# ReferencedEnum Enum + +## Valores +| Value | Description | +|-------|-------------| +| VALUE1 | | +| VALUE2 | | +| VALUE3 | | \ No newline at end of file diff --git a/examples/translation/docs/miscellaneous/SampleException.md b/examples/translation/docs/miscellaneous/SampleException.md new file mode 100644 index 00000000..e295cbc1 --- /dev/null +++ b/examples/translation/docs/miscellaneous/SampleException.md @@ -0,0 +1,21 @@ +# SampleException Clase + +This is a sample exception. + +**Usage** + +You can use the exception the following way. +You can also take a look at [SampleClass](../samplegroup/SampleClass.md) to see how it is used. +This is a dangerous HTML tag: <script>alert('Hello');</script> + +```apex +try { + throw new SampleException(); +} catch (SampleException e) { + System.debug('Caught exception'); +} +``` + +**Herencia** + +Exception \ No newline at end of file diff --git a/examples/translation/docs/miscellaneous/SampleInterface.md b/examples/translation/docs/miscellaneous/SampleInterface.md new file mode 100644 index 00000000..d581f450 --- /dev/null +++ b/examples/translation/docs/miscellaneous/SampleInterface.md @@ -0,0 +1,109 @@ +# SampleInterface Interfaz + +`NAMESPACEACCESSIBLE` + +This is a sample interface + +**Mermaid** + +graph TD +A[SampleInterface] -->|extends| B[ParentInterface] +B -->|extends| C[GrandParentInterface] +C -->|extends| D[GreatGrandParentInterface] + +**Autor** John Doe + +**Date** 2020-01-01 + +**See** [SampleEnum](../sample-enums/SampleEnum.md) + +**See** [ReferencedEnum](ReferencedEnum.md) + +## Example +SampleInterface sampleInterface = new SampleInterface(); +sampleInterface.sampleMethod(); + +**Extends** +[ParentInterface](ParentInterface.md) + +## Métodos +### `sampleMethod()` + +`NAMESPACEACCESSIBLE` + +This is a sample method + +**Custom Tag** + +This is a custom tag + +**Another Custom Tag** + +This is another custom tag + +**Mermaid** + +graph TD +A[SampleInterface] -->|extends| B[ParentInterface] +B -->|extends| C[GrandParentInterface] +C -->|extends| D[GreatGrandParentInterface] + +#### Firma +```apex +public String sampleMethod() +``` + +#### Tipo de Retorno +**String** + +Some return value + +#### Lanza +[SampleException](SampleException.md): This is a sample exception + +AnotherSampleException: This is another sample exception + +#### Example +SampleInterface sampleInterface = new SampleInterface(); +sampleInterface.sampleMethod(); + +--- + +### `sampleMethodWithParams(param1, param2, theEnum)` + +`NAMESPACEACCESSIBLE` +`DEPRECATED` + +This is a sample method with parameters +Sometimes it won't be possible to find a NonExistent link. + +#### Firma +```apex +public SampleEnum sampleMethodWithParams(String param1, Integer param2, SampleEnum theEnum) +``` + +#### Parámetros +| Name | Type | Description | +|------|------|-------------| +| param1 | String | This is the first parameter | +| param2 | Integer | This is the second parameter | +| theEnum | [SampleEnum](../sample-enums/SampleEnum.md) | This is an enum parameter | + +#### Tipo de Retorno +**[SampleEnum](../sample-enums/SampleEnum.md)** + +Some return value + +--- + +### `sampleParentMethod()` + +*Inherited* + +#### Firma +```apex +public void sampleParentMethod() +``` + +#### Tipo de Retorno +**void** \ No newline at end of file diff --git a/examples/translation/docs/miscellaneous/Url.md b/examples/translation/docs/miscellaneous/Url.md new file mode 100644 index 00000000..2239ff08 --- /dev/null +++ b/examples/translation/docs/miscellaneous/Url.md @@ -0,0 +1,310 @@ +# Url Clase + +Represents a uniform resource locator (URL) and provides access to parts of the URL. +Enables access to the base URL used to access your Salesforce org. + +**Usage** + +Use the methods of the `System.URL` class to create links to objects in your organization. Such objects can be files, images, +logos, or records that you want to include in external emails, in activities, or in Chatter posts. For example, you can create +a link to a file uploaded as an attachment to a Chatter post by concatenating the Salesforce base URL with the file ID: + +```apex +// Get a file uploaded through Chatter. +ContentDocument doc = [SELECT Id FROM ContentDocument + WHERE Title = 'myfile']; +// Create a link to the file. +String fullFileURL = URL.getOrgDomainURL().toExternalForm() + + '/' + doc.id; +System.debug(fullFileURL); +``` + + +The following example creates a link to a Salesforce record. The full URL is created by concatenating the Salesforce base +URL with the record ID. + +```apex +Account acct = [SELECT Id FROM Account WHERE Name = 'Acme' LIMIT 1]; +String fullRecordURL = URL.getOrgDomainURL().toExternalForm() + '/' + acct.Id; +``` + +**Version Behavior Changes** + +In API version 41.0 and later, Apex URL objects are represented by the java.net.URI type, not the java.net.URL type. + +The API version in which the URL object was instantiated determines the behavior of subsequent method calls to the +specific instance. Salesforce strongly encourages you to use API 41.0 and later versions for fully RFC-compliant URL +parsing that includes proper handling of edge cases of complex URL structures. API 41.0 and later versions also enforce +that inputs are valid, RFC-compliant URL or URI strings. + +* [URL Constructors](https://developer.salesforce.com/docs/atlas.en-us.apexref.meta/apexref/apex_methods_system_url.htm#apex_System_URL_constructors) +* [URL Methods](https://developer.salesforce.com/docs/atlas.en-us.apexref.meta/apexref/apex_methods_system_url.htm#apex_System_URL_methods) + +**See Also** +* [URL Class](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_url.htm) + +## Example +In this example, the base URL and the full request URL of the current Salesforce server instance are retrieved. Next, a URL +pointing to a specific account object is created. Finally, components of the base and full URL are obtained. This example +prints out all the results to the debug log output. + +```apex +// Create a new account called Acme that we will create a link for later. +Account myAccount = new Account(Name='Acme'); +insert myAccount; + +// Get the base URL. +String sfdcBaseURL = URL.getOrgDomainURL().toExternalForm(); +System.debug('Base URL: ' + sfdcBaseURL ); + +// Get the URL for the current request. +String currentRequestURL = URL.getCurrentRequestUrl().toExternalForm(); +System.debug('Current request URL: ' + currentRequestURL); + +// Create the account URL from the base URL. +String accountURL = URL.getOrgDomainURL().toExternalForm() + + '/' + myAccount.Id; +System.debug('URL of a particular account: ' + accountURL); + +// Get some parts of the base URL. +System.debug('Host: ' + URL.getOrgDomainURL().getHost()); +System.debug('Protocol: ' + URL.getOrgDomainURL().getProtocol()); + +// Get the query string of the current request. +System.debug('Query: ' + URL.getCurrentRequestUrl().getQuery()); +``` + +## Constructores +### `Url(spec)` + +Creates a new instance of the URL class using the specified string representation of the URL. + +#### Firma +```apex +global Url(String spec) +``` + +#### Parámetros +| Name | Type | Description | +|------|------|-------------| +| spec | String | The string to parse as a URL. | + +--- + +### `Url(context, spec)` + +Creates a new instance of the URL class by parsing the specified spec within the specified context. + +**Usage** + +The new URL is created from the given context URL and the spec argument as described in RFC2396 "Uniform Resource Identifiers : Generic * Syntax" : +```xml +://?# +``` + + +For more information about the arguments of this constructor, see the corresponding URL(java.net.URL, java.lang.String) constructor for Java. + +#### Firma +```apex +global Url(Url context, String spec) +``` + +#### Parámetros +| Name | Type | Description | +|------|------|-------------| +| context | [Url](Url.md) | The context in which to parse the specification. | +| spec | String | The string to parse as a URL. | + +--- + +### `Url(protocol, host, file)` + +Creates a new instance of the URL class using the specified protocol, host, and file on the host. The default port for the specified protocol is used. + +#### Firma +```apex +global Url(String protocol, String host, String file) +``` + +#### Parámetros +| Name | Type | Description | +|------|------|-------------| +| protocol | String | The protocol name for this URL. | +| host | String | The host name for this URL. | +| file | String | The file name for this URL. | + +--- + +### `Url(protocol, host, port, file)` + +Creates a new instance of the URL class using the specified protocol, host, port number, and file on the host. + +#### Firma +```apex +global Url(String protocol, String host, Integer port, String file) +``` + +#### Parámetros +| Name | Type | Description | +|------|------|-------------| +| protocol | String | The protocol name for this URL. | +| host | String | The host name for this URL. | +| port | Integer | The port number for this URL. | +| file | String | The file name for this URL. | + +## Métodos +### `getAuthority()` + +Returns the authority portion of the current URL. + +#### Firma +```apex +global String getAuthority() +``` + +#### Tipo de Retorno +**String** + +The authority portion of the current URL. + +--- + +### `getCurrentRequestUrl()` + +Returns the URL of an entire request on a Salesforce instance. + +**Usage** + +An example of a URL for an entire request is https://yourInstance.salesforce.com/apex/myVfPage.apexp. + +#### Firma +```apex +global static Url getCurrentRequestUrl() +``` + +#### Tipo de Retorno +**[Url](Url.md)** + +The URL of the entire request. + +--- + +### `getDefPort()` + +Returns the default port number of the protocol associated with the current URL. + +**Usage** + +Returns -1 if the URL scheme or the stream protocol handler for the URL doesn't define a default port number. + +#### Firma +```apex +global Integer getDefPort() +``` + +#### Tipo de Retorno +**Integer** + +The default port number of the protocol associated with the current URL. + +--- + +### `getFile()` + +Returns the file name of the current URL. + +#### Firma +```apex +global String getFile() +``` + +#### Tipo de Retorno +**String** + +The file name of the current URL. + +--- + +### `getFileFieldURL(entityId, fieldName)` + +Returns the download URL for a file attachment. + +#### Firma +```apex +global static String getFileFieldURL(String entityId, String fieldName) +``` + +#### Parámetros +| Name | Type | Description | +|------|------|-------------| +| entityId | String | Specifies the ID of the entity that holds the file data. | +| fieldName | String | Specifies the API name of a file field component, such as `AttachmentBody` . | + +#### Tipo de Retorno +**String** + +The download URL for the file attachment. + +#### Example +String fileURL = +URL.getFileFieldURL( +'087000000000123' , +'AttachmentBody'); + +--- + +### `getHost()` + +Returns the host name of the current URL. + +#### Firma +```apex +global String getHost() +``` + +#### Tipo de Retorno +**String** + +The host name of the current URL. + +--- + +### `getOrgDomainUrl()` + +Returns the canonical URL for your org. For example, https://MyDomainName.my.salesforce.com. + +**Usage** + +Use getOrgDomainUrl() to interact with Salesforce REST and SOAP APIs in Apex code. Get endpoints for User Interface API calls, for creating and customizing picklist value sets and custom fields, and more. + + `getOrgDomainUrl()` can access the domain URL only for the org in which the Apex code is running. + +You don't need a RemoteSiteSetting for your org to interact with the Salesforce APIs using domain URLs retrieved with this method. + +**See Also** + +* [Lightning Aura Components Developer Guide: Making API Calls from Apex](https://developer.salesforce.com/docs/atlas.en-us.250.0.lightning.meta/lightning/apex_api_calls.htm) + +#### Firma +```apex +global static Url getOrgDomainUrl() +``` + +#### Tipo de Retorno +**[Url](Url.md)** + +getOrgDomainUrl() always returns the login URL for your org, regardless of context. Use that URL when making API calls to your org. + +#### Example +This example uses the Salesforce REST API to get organization limit values. For information on limits, see Limits in the REST API Developer Guide. + +```apex +Http h = new Http(); +HttpRequest req = new HttpRequest(); +req.setEndpoint(Url.getOrgDomainUrl().toExternalForm() + + '/services/data/v44.0/limits'); +req.setMethod('GET'); +req.setHeader('Authorization', 'Bearer ' + UserInfo.getSessionId()); +HttpResponse res = h.send(req); +``` \ No newline at end of file diff --git a/examples/translation/docs/sample-enums/SampleEnum.md b/examples/translation/docs/sample-enums/SampleEnum.md new file mode 100644 index 00000000..bd3e37f2 --- /dev/null +++ b/examples/translation/docs/sample-enums/SampleEnum.md @@ -0,0 +1,33 @@ +# SampleEnum Enum + +`NAMESPACEACCESSIBLE` + +This is a sample enum. This references [ReferencedEnum](../miscellaneous/ReferencedEnum.md) . + +This description has several lines + +**Some Custom** + +Test. I can also have a [ReferencedEnum](../miscellaneous/ReferencedEnum.md) here. +And it can be multiline. + +**Mermaid** + +graph TD +A[SampleEnum] -->|references| B[ReferencedEnum] +B -->|referenced by| A + +**Group** Sample Enums + +**Autor** John Doe + +**Date** 2022-01-01 + +**See** [ReferencedEnum](../miscellaneous/ReferencedEnum.md) + +## Valores +| Value | Description | +|-------|-------------| +| VALUE1 | This is value 1 | +| VALUE2 | This is value 2 | +| VALUE3 | This is value 3 | \ No newline at end of file diff --git a/examples/translation/docs/samplegroup/SampleClass.md b/examples/translation/docs/samplegroup/SampleClass.md new file mode 100644 index 00000000..1ec8d641 --- /dev/null +++ b/examples/translation/docs/samplegroup/SampleClass.md @@ -0,0 +1,159 @@ +# SampleClass Clase +`virtual` + +aliquip ex sunt officia ullamco anim deserunt magna aliquip nisi eiusmod in sit officia veniam ex +**deserunt** ea officia exercitation laboris enim in duis quis enim eiusmod eu amet cupidatat. + +**Internal** + +This should not appear in the docs + +**Group** SampleGroup + +**See** [Event__c](../custom-objects/Event__c.md) + +## Example +SampleClass sample = new SampleClass(); +sample.doSomething(); + +**Herencia** + +[BaseClass](../miscellaneous/BaseClass.md) + +**Implementa** + +[SampleInterface](../miscellaneous/SampleInterface.md), +[ParentInterface](../miscellaneous/ParentInterface.md) + +## Campos +### `sampleEnumFromBase` + +*Inherited* + +#### Firma +```apex +public sampleEnumFromBase +``` + +#### Tipo +[SampleEnum](../sample-enums/SampleEnum.md) + +## Propiedades +### Group Name +#### `someProperty` + +##### Firma +```apex +public someProperty +``` + +##### Tipo +String + +## Constructores +### Other +#### `SampleClass()` + +This is a sample constructor. + +##### Firma +```apex +public SampleClass() +``` + +### Other Constructors +#### `SampleClass(name)` + +##### Firma +```apex +public SampleClass(String name) +``` + +##### Parámetros +| Name | Type | Description | +|------|------|-------------| +| name | String | | + +## Métodos +### Available Methods +#### `doSomething()` + +##### Firma +```apex +public void doSomething() +``` + +##### Tipo de Retorno +**void** + +### Deprecated Methods +#### `sayHello()` + +`DEPRECATED` + +This is a sample method. + +##### Firma +```apex +public virtual String sayHello() +``` + +##### Tipo de Retorno +**String** + +A string value. + +##### Example +SampleClass sample = new SampleClass(); +sample.doSomething(); + +## Classes +### SomeInnerClass Clase + +#### Campos +##### `someInnerField` + +###### Firma +```apex +public someInnerField +``` + +###### Tipo +String + +#### Métodos +##### `doSomething()` + +###### Firma +```apex +public void doSomething() +``` + +###### Tipo de Retorno +**void** + +## Enums +### SomeEnum Enum + +This enum is used for foo and bar. + +#### Valores +| Value | Description | +|-------|-------------| +| TEST_1 | This is a test. | +| TEST_2 | | +| TEST_3 | | + +## Interfaces +### SomeInterface Interfaz + +#### Métodos +##### `doSomething()` + +###### Firma +```apex +public void doSomething() +``` + +###### Tipo de Retorno +**void** \ No newline at end of file diff --git a/examples/translation/force-app/classes/BaseClass.cls b/examples/translation/force-app/classes/BaseClass.cls new file mode 100644 index 00000000..e39a71ac --- /dev/null +++ b/examples/translation/force-app/classes/BaseClass.cls @@ -0,0 +1,3 @@ +public abstract class BaseClass { + public SampleEnum sampleEnumFromBase; +} diff --git a/examples/translation/force-app/classes/BaseClass.cls-meta.xml b/examples/translation/force-app/classes/BaseClass.cls-meta.xml new file mode 100644 index 00000000..998805a8 --- /dev/null +++ b/examples/translation/force-app/classes/BaseClass.cls-meta.xml @@ -0,0 +1,5 @@ + + + 62.0 + Active + diff --git a/examples/translation/force-app/classes/MultiInheritanceClass.cls b/examples/translation/force-app/classes/MultiInheritanceClass.cls new file mode 100644 index 00000000..b41cabad --- /dev/null +++ b/examples/translation/force-app/classes/MultiInheritanceClass.cls @@ -0,0 +1 @@ +public class MultiInheritanceClass extends SampleClass {} diff --git a/examples/translation/force-app/classes/MultiInheritanceClass.cls-meta.xml b/examples/translation/force-app/classes/MultiInheritanceClass.cls-meta.xml new file mode 100644 index 00000000..998805a8 --- /dev/null +++ b/examples/translation/force-app/classes/MultiInheritanceClass.cls-meta.xml @@ -0,0 +1,5 @@ + + + 62.0 + Active + diff --git a/examples/translation/force-app/classes/ParentInterface.cls b/examples/translation/force-app/classes/ParentInterface.cls new file mode 100644 index 00000000..7d222069 --- /dev/null +++ b/examples/translation/force-app/classes/ParentInterface.cls @@ -0,0 +1,3 @@ +public interface ParentInterface { + void sampleParentMethod(); +} diff --git a/examples/translation/force-app/classes/ParentInterface.cls-meta.xml b/examples/translation/force-app/classes/ParentInterface.cls-meta.xml new file mode 100644 index 00000000..998805a8 --- /dev/null +++ b/examples/translation/force-app/classes/ParentInterface.cls-meta.xml @@ -0,0 +1,5 @@ + + + 62.0 + Active + diff --git a/examples/translation/force-app/classes/ReferencedEnum.cls b/examples/translation/force-app/classes/ReferencedEnum.cls new file mode 100644 index 00000000..af79a1c8 --- /dev/null +++ b/examples/translation/force-app/classes/ReferencedEnum.cls @@ -0,0 +1,5 @@ +public enum ReferencedEnum { + VALUE1, + VALUE2, + VALUE3 +} diff --git a/examples/translation/force-app/classes/ReferencedEnum.cls-meta.xml b/examples/translation/force-app/classes/ReferencedEnum.cls-meta.xml new file mode 100644 index 00000000..998805a8 --- /dev/null +++ b/examples/translation/force-app/classes/ReferencedEnum.cls-meta.xml @@ -0,0 +1,5 @@ + + + 62.0 + Active + diff --git a/examples/translation/force-app/classes/Url.cls b/examples/translation/force-app/classes/Url.cls new file mode 100644 index 00000000..ddea0250 --- /dev/null +++ b/examples/translation/force-app/classes/Url.cls @@ -0,0 +1,198 @@ +/** + * @description Represents a uniform resource locator (URL) and provides access to parts of the URL. + * Enables access to the base URL used to access your Salesforce org. + * + * @usage + * Use the methods of the `System.URL` class to create links to objects in your organization. Such objects can be files, images, + * logos, or records that you want to include in external emails, in activities, or in Chatter posts. For example, you can create + * a link to a file uploaded as an attachment to a Chatter post by concatenating the Salesforce base URL with the file ID: + * + * ```apex + * // Get a file uploaded through Chatter. + * ContentDocument doc = [SELECT Id FROM ContentDocument + * WHERE Title = 'myfile']; + * // Create a link to the file. + * String fullFileURL = URL.getOrgDomainURL().toExternalForm() + + * '/' + doc.id; + * System.debug(fullFileURL); + * ``` + * + * The following example creates a link to a Salesforce record. The full URL is created by concatenating the Salesforce base + * URL with the record ID. + * + * ```apex + * Account acct = [SELECT Id FROM Account WHERE Name = 'Acme' LIMIT 1]; + * String fullRecordURL = URL.getOrgDomainURL().toExternalForm() + '/' + acct.Id; + * ``` + * + * @example + * In this example, the base URL and the full request URL of the current Salesforce server instance are retrieved. Next, a URL + * pointing to a specific account object is created. Finally, components of the base and full URL are obtained. This example + * prints out all the results to the debug log output. + * + * ```apex + * // Create a new account called Acme that we will create a link for later. + * Account myAccount = new Account(Name='Acme'); + * insert myAccount; + * + * // Get the base URL. + * String sfdcBaseURL = URL.getOrgDomainURL().toExternalForm(); + * System.debug('Base URL: ' + sfdcBaseURL ); + * + * // Get the URL for the current request. + * String currentRequestURL = URL.getCurrentRequestUrl().toExternalForm(); + * System.debug('Current request URL: ' + currentRequestURL); + * + * // Create the account URL from the base URL. + * String accountURL = URL.getOrgDomainURL().toExternalForm() + + * '/' + myAccount.Id; + * System.debug('URL of a particular account: ' + accountURL); + * + * // Get some parts of the base URL. + * System.debug('Host: ' + URL.getOrgDomainURL().getHost()); + * System.debug('Protocol: ' + URL.getOrgDomainURL().getProtocol()); + * + * // Get the query string of the current request. + * System.debug('Query: ' + URL.getCurrentRequestUrl().getQuery()); + * ``` + * + * @version-behavior-changes + * In API version 41.0 and later, Apex URL objects are represented by the java.net.URI type, not the java.net.URL type. + * + * The API version in which the URL object was instantiated determines the behavior of subsequent method calls to the + * specific instance. Salesforce strongly encourages you to use API 41.0 and later versions for fully RFC-compliant URL + * parsing that includes proper handling of edge cases of complex URL structures. API 41.0 and later versions also enforce + * that inputs are valid, RFC-compliant URL or URI strings. + * + * * [URL Constructors](https://developer.salesforce.com/docs/atlas.en-us.apexref.meta/apexref/apex_methods_system_url.htm#apex_System_URL_constructors) + * * [URL Methods](https://developer.salesforce.com/docs/atlas.en-us.apexref.meta/apexref/apex_methods_system_url.htm#apex_System_URL_methods) + * + * **See Also** + * * [URL Class](https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_classes_url.htm) + */ +global class Url { + /** + * @description Creates a new instance of the URL class using the specified string representation of the URL. + * @param spec The string to parse as a URL. + */ + global Url(String spec) { } + + /** + * @description Creates a new instance of the URL class by parsing the specified spec within the specified context. + * @param context The context in which to parse the specification. + * @param spec The string to parse as a URL. + * + * @usage + * The new URL is created from the given context URL and the spec argument as described in RFC2396 "Uniform Resource Identifiers : Generic * Syntax" : + * ```xml + * ://?# + * ``` + * + * For more information about the arguments of this constructor, see the corresponding URL(java.net.URL, java.lang.String) constructor for Java. + */ + global Url(Url context, String spec) { } + + /** + * @description Creates a new instance of the URL class using the specified protocol, host, and file on the host. The default port for the specified protocol is used. + * @param protocol The protocol name for this URL. + * @param host The host name for this URL. + * @param file The file name for this URL. + */ + global Url(String protocol, String host, String file) {} + + /** + * @description Creates a new instance of the URL class using the specified protocol, host, port number, and file on the host. + * @param protocol The protocol name for this URL. + * @param host The host name for this URL. + * @param port The port number for this URL. + * @param file The file name for this URL. + */ + global Url(String protocol, String host, Integer port, String file) {} + + /** + * @description Returns the authority portion of the current URL. + * @return The authority portion of the current URL. + */ + global String getAuthority() { + return null; + } + + /** + * @description Returns the URL of an entire request on a Salesforce instance. + * @return The URL of the entire request. + * @usage An example of a URL for an entire request is https://yourInstance.salesforce.com/apex/myVfPage.apexp. + */ + global static Url getCurrentRequestUrl() { + return null; + } + + /** + * @description Returns the default port number of the protocol associated with the current URL. + * @return The default port number of the protocol associated with the current URL. + * @usage Returns -1 if the URL scheme or the stream protocol handler for the URL doesn't define a default port number. + */ + global Integer getDefPort() { + return null; + } + + /** + * @description Returns the file name of the current URL. + * @return The file name of the current URL. + */ + global String getFile() { + return null; + } + + /** + * @description Returns the download URL for a file attachment. + * @param entityId Specifies the ID of the entity that holds the file data. + * @param fieldName Specifies the API name of a file field component, such as `AttachmentBody`. + * @return The download URL for the file attachment. + * @example + * String fileURL = + * URL.getFileFieldURL( + * '087000000000123' , + * 'AttachmentBody'); + */ + global static String getFileFieldURL(String entityId, String fieldName) { + return null; + } + + /** + * @description Returns the host name of the current URL. + * @return The host name of the current URL. + */ + global String getHost() { + return null; + } + + /** + * @description Returns the canonical URL for your org. For example, https://MyDomainName.my.salesforce.com. + * @return getOrgDomainUrl() always returns the login URL for your org, regardless of context. Use that URL when making API calls to your org. + * @usage + * Use getOrgDomainUrl() to interact with Salesforce REST and SOAP APIs in Apex code. Get endpoints for User Interface API calls, for creating and customizing picklist value sets and custom fields, and more. + * + * `getOrgDomainUrl()` can access the domain URL only for the org in which the Apex code is running. + * + * You don't need a RemoteSiteSetting for your org to interact with the Salesforce APIs using domain URLs retrieved with this method. + * + * @example + * This example uses the Salesforce REST API to get organization limit values. For information on limits, see Limits in the REST API Developer Guide. + * + * ```apex + * Http h = new Http(); + * HttpRequest req = new HttpRequest(); + * req.setEndpoint(Url.getOrgDomainUrl().toExternalForm() + * + '/services/data/v44.0/limits'); + * req.setMethod('GET'); + * req.setHeader('Authorization', 'Bearer ' + UserInfo.getSessionId()); + * HttpResponse res = h.send(req); + * ``` + * + * @see-also + * * [Lightning Aura Components Developer Guide: Making API Calls from Apex](https://developer.salesforce.com/docs/atlas.en-us.250.0.lightning.meta/lightning/apex_api_calls.htm) + */ + global static Url getOrgDomainUrl() { + return null; + } +} diff --git a/examples/translation/force-app/classes/Url.cls-meta.xml b/examples/translation/force-app/classes/Url.cls-meta.xml new file mode 100644 index 00000000..998805a8 --- /dev/null +++ b/examples/translation/force-app/classes/Url.cls-meta.xml @@ -0,0 +1,5 @@ + + + 62.0 + Active + diff --git a/examples/translation/force-app/classes/feature-a/SampleClass.cls b/examples/translation/force-app/classes/feature-a/SampleClass.cls new file mode 100644 index 00000000..1b3956bc --- /dev/null +++ b/examples/translation/force-app/classes/feature-a/SampleClass.cls @@ -0,0 +1,74 @@ +/** + * @description aliquip ex sunt officia ullamco anim deserunt magna aliquip nisi eiusmod in sit officia veniam ex + * **deserunt** ea officia exercitation laboris enim in duis quis enim eiusmod eu amet cupidatat. + * @group SampleGroup + * @see Event__c + * @example + * SampleClass sample = new SampleClass(); + * sample.doSomething(); + * @internal This should not appear in the docs + */ +public with sharing virtual class SampleClass extends BaseClass implements SampleInterface, ParentInterface { + // @start-group Group Name + /** + * @description This is a sample field. + */ + private final String name; + public String someProperty { get; private set; } + // @end-group + + /** + * @description This is a sample constructor. + */ + public SampleClass() {} + + // @start-group Other Constructors + public SampleClass(String name) { + this.name = name; + } + // @end-group + + // @start-group Available Methods + public void doSomething() { + System.debug('Doing something'); + } + // @end-group + + // @start-group Deprecated Methods + + /** + * @description This is a sample method. + * @return A string value. + * @example + * SampleClass sample = new SampleClass(); + * sample.doSomething(); + */ + @Deprecated + public virtual String sayHello() { + return 'Hello'; + } + + // @end-group + + public class SomeInnerClass { + public String someInnerField; + + public void doSomething() { + System.debug('Doing something'); + } + } + + /** + * @description This enum is used for foo and bar. + */ + public enum SomeEnum { + /** @description This is a test. */ + TEST_1, + TEST_2, + TEST_3 + } + + public interface SomeInterface { + void doSomething(); + } +} diff --git a/examples/translation/force-app/classes/feature-a/SampleClass.cls-meta.xml b/examples/translation/force-app/classes/feature-a/SampleClass.cls-meta.xml new file mode 100644 index 00000000..998805a8 --- /dev/null +++ b/examples/translation/force-app/classes/feature-a/SampleClass.cls-meta.xml @@ -0,0 +1,5 @@ + + + 62.0 + Active + diff --git a/examples/translation/force-app/classes/feature-a/SampleEnum.cls b/examples/translation/force-app/classes/feature-a/SampleEnum.cls new file mode 100644 index 00000000..7e857ed6 --- /dev/null +++ b/examples/translation/force-app/classes/feature-a/SampleEnum.cls @@ -0,0 +1,30 @@ +/** + * @description This is a sample enum. This references {@link ReferencedEnum}. + * + * This description has several lines + * @group Sample Enums + * @author John Doe + * @date 2022-01-01 + * @some-custom Test. I can also have a {@link ReferencedEnum} here. + * And it can be multiline. + * @see ReferencedEnum + * @mermaid + * graph TD + * A[SampleEnum] -->|references| B[ReferencedEnum] + * B -->|referenced by| A + */ +@NamespaceAccessible +public enum SampleEnum { + /** + * @description This is value 1 + */ + VALUE1, + /** + * @description This is value 2 + */ + VALUE2, + /** + * @description This is value 3 + */ + VALUE3 +} diff --git a/examples/translation/force-app/classes/feature-a/SampleEnum.cls-meta.xml b/examples/translation/force-app/classes/feature-a/SampleEnum.cls-meta.xml new file mode 100644 index 00000000..998805a8 --- /dev/null +++ b/examples/translation/force-app/classes/feature-a/SampleEnum.cls-meta.xml @@ -0,0 +1,5 @@ + + + 62.0 + Active + diff --git a/examples/translation/force-app/classes/feature-a/SampleException.cls b/examples/translation/force-app/classes/feature-a/SampleException.cls new file mode 100644 index 00000000..c05dd40f --- /dev/null +++ b/examples/translation/force-app/classes/feature-a/SampleException.cls @@ -0,0 +1,17 @@ +/** + * @description This is a sample exception. + * @usage + * + * You can use the exception the following way. + * You can also take a look at {@link SampleClass} to see how it is used. + * This is a dangerous HTML tag: + * + * ``` + * try { + * throw new SampleException(); + * } catch (SampleException e) { + * System.debug('Caught exception'); + * } + * ``` + */ +public class SampleException extends Exception {} diff --git a/examples/translation/force-app/classes/feature-a/SampleException.cls-meta.xml b/examples/translation/force-app/classes/feature-a/SampleException.cls-meta.xml new file mode 100644 index 00000000..998805a8 --- /dev/null +++ b/examples/translation/force-app/classes/feature-a/SampleException.cls-meta.xml @@ -0,0 +1,5 @@ + + + 62.0 + Active + diff --git a/examples/translation/force-app/classes/feature-a/SampleInterface.cls b/examples/translation/force-app/classes/feature-a/SampleInterface.cls new file mode 100644 index 00000000..2fbaab8d --- /dev/null +++ b/examples/translation/force-app/classes/feature-a/SampleInterface.cls @@ -0,0 +1,46 @@ +/** + * @description This is a sample interface + * @author John Doe + * @date 2020-01-01 + * @see SampleEnum + * @see ReferencedEnum + * @mermaid + * graph TD + * A[SampleInterface] -->|extends| B[ParentInterface] + * B -->|extends| C[GrandParentInterface] + * C -->|extends| D[GreatGrandParentInterface] + * @example + * SampleInterface sampleInterface = new SampleInterface(); + * sampleInterface.sampleMethod(); + */ +@NamespaceAccessible +public interface SampleInterface extends ParentInterface { + /** + * @description This is a sample method + * @return Some return value + * @throws SampleException This is a sample exception + * @throws AnotherSampleException This is another sample exception + * @custom-tag This is a custom tag + * @another-custom-tag This is another custom tag + * @mermaid + * graph TD + * A[SampleInterface] -->|extends| B[ParentInterface] + * B -->|extends| C[GrandParentInterface] + * C -->|extends| D[GreatGrandParentInterface] + * @example + * SampleInterface sampleInterface = new SampleInterface(); + * sampleInterface.sampleMethod(); + */ + String sampleMethod(); + + /** + * @description This is a sample method with parameters + * Sometimes it won't be possible to find a {@link NonExistent} link. + * @param param1 This is the first parameter + * @param param2 This is the second parameter + * @param theEnum This is an enum parameter + * @return Some return value + */ + @Deprecated + SampleEnum sampleMethodWithParams(String param1, Integer param2, SampleEnum theEnum); +} diff --git a/examples/translation/force-app/classes/feature-a/SampleInterface.cls-meta.xml b/examples/translation/force-app/classes/feature-a/SampleInterface.cls-meta.xml new file mode 100644 index 00000000..998805a8 --- /dev/null +++ b/examples/translation/force-app/classes/feature-a/SampleInterface.cls-meta.xml @@ -0,0 +1,5 @@ + + + 62.0 + Active + diff --git a/examples/translation/force-app/objects/Account/Account.object-meta.xml b/examples/translation/force-app/objects/Account/Account.object-meta.xml new file mode 100644 index 00000000..5f969ba5 --- /dev/null +++ b/examples/translation/force-app/objects/Account/Account.object-meta.xml @@ -0,0 +1,90 @@ + + + + CallHighlightAction + Default + + + CancelEdit + Default + + + Delete + Default + + + Edit + Default + + + EmailHighlightAction + Default + + + EnableCustomerPortalUser + Default + + + List + Default + + + ListClean + Default + + + New + Default + + + RequestUpdate + Default + + + SaveEdit + Default + + + SmsHighlightAction + Default + + + Tab + Default + + + View + Account_Record_Page + Large + false + Flexipage + + + ViewCustomerPortalUser + Default + + + WebsiteHighlightAction + Default + + Account_Compact_Layout + true + true + false + + ACCOUNT.NAME + ACCOUNT.ADDRESS1_CITY + ACCOUNT.PHONE1 + ACCOUNT.NAME + CORE.USERS.ALIAS + ACCOUNT.TYPE + ACCOUNT.NAME + CORE.USERS.ALIAS + ACCOUNT.TYPE + ACCOUNT.PHONE1 + ACCOUNT.NAME + ACCOUNT.PHONE1 + CORE.USERS.ALIAS + + ReadWrite + diff --git a/examples/translation/force-app/objects/Contact/Contact.object-meta.xml b/examples/translation/force-app/objects/Contact/Contact.object-meta.xml new file mode 100644 index 00000000..0d11ee1b --- /dev/null +++ b/examples/translation/force-app/objects/Contact/Contact.object-meta.xml @@ -0,0 +1,3 @@ + + + diff --git a/examples/translation/force-app/objects/Contact/fields/PhotoUrl__c.field-meta.xml b/examples/translation/force-app/objects/Contact/fields/PhotoUrl__c.field-meta.xml new file mode 100644 index 00000000..a9117781 --- /dev/null +++ b/examples/translation/force-app/objects/Contact/fields/PhotoUrl__c.field-meta.xml @@ -0,0 +1,9 @@ + + + PhotoUrl__c + false + + false + false + Url + diff --git a/examples/translation/force-app/objects/Event__c/Event__c.object-meta.xml b/examples/translation/force-app/objects/Event__c/Event__c.object-meta.xml new file mode 100644 index 00000000..d30dde5c --- /dev/null +++ b/examples/translation/force-app/objects/Event__c/Event__c.object-meta.xml @@ -0,0 +1,167 @@ + + + + Accept + Default + + + Accept + Large + Default + + + Accept + Small + Default + + + CancelEdit + Default + + + CancelEdit + Large + Default + + + CancelEdit + Small + Default + + + Clone + Default + + + Clone + Large + Default + + + Clone + Small + Default + + + Delete + Default + + + Delete + Large + Default + + + Delete + Small + Default + + + Edit + Default + + + Edit + Large + Default + + + Edit + Small + Default + + + List + Default + + + List + Large + Default + + + List + Small + Default + + + New + Default + + + New + Large + Default + + + New + Small + Default + + + SaveEdit + Default + + + SaveEdit + Large + Default + + + SaveEdit + Small + Default + + + Tab + Default + + + Tab + Large + Default + + + Tab + Small + Default + + + View + Default + + + View + Large + Default + + + View + Small + Default + + false + SYSTEM + Deployed + false + true + false + false + false + false + false + true + true + Private + + + + Text + + Events + Represents an event that people can register for. + + ReadWrite + Vowel + Public + diff --git a/examples/translation/force-app/objects/Event__c/fields/Description__c.field-meta.xml b/examples/translation/force-app/objects/Event__c/fields/Description__c.field-meta.xml new file mode 100644 index 00000000..c1b682a4 --- /dev/null +++ b/examples/translation/force-app/objects/Event__c/fields/Description__c.field-meta.xml @@ -0,0 +1,10 @@ + + + Description__c + false + + 32768 + false + LongTextArea + 10 + diff --git a/examples/translation/force-app/objects/Event__c/fields/End_Date__c.field-meta.xml b/examples/translation/force-app/objects/Event__c/fields/End_Date__c.field-meta.xml new file mode 100644 index 00000000..422a0003 --- /dev/null +++ b/examples/translation/force-app/objects/Event__c/fields/End_Date__c.field-meta.xml @@ -0,0 +1,9 @@ + + + End_Date__c + false + + true + false + Date + diff --git a/examples/translation/force-app/objects/Event__c/fields/Location__c.field-meta.xml b/examples/translation/force-app/objects/Event__c/fields/Location__c.field-meta.xml new file mode 100644 index 00000000..b8f32121 --- /dev/null +++ b/examples/translation/force-app/objects/Event__c/fields/Location__c.field-meta.xml @@ -0,0 +1,11 @@ + + + Location__c + false + false + + true + 3 + false + Location + diff --git a/examples/translation/force-app/objects/Event__c/fields/Social_Security_Number__c.field-meta.xml b/examples/translation/force-app/objects/Event__c/fields/Social_Security_Number__c.field-meta.xml new file mode 100644 index 00000000..b463d465 --- /dev/null +++ b/examples/translation/force-app/objects/Event__c/fields/Social_Security_Number__c.field-meta.xml @@ -0,0 +1,13 @@ + + + Social_Security_Number__c + false + + You indicated the approval for storage of your social security number. + Used to store the U.S. social security number in 9 digit format. + 9 + false + Text + PII + Internal + diff --git a/examples/translation/force-app/objects/Event__c/fields/Start_Date__c.field-meta.xml b/examples/translation/force-app/objects/Event__c/fields/Start_Date__c.field-meta.xml new file mode 100644 index 00000000..81fb3f6d --- /dev/null +++ b/examples/translation/force-app/objects/Event__c/fields/Start_Date__c.field-meta.xml @@ -0,0 +1,9 @@ + + + Start_Date__c + false + + true + false + Date + diff --git a/examples/translation/force-app/objects/Event__c/fields/Tag_Line__c.field-meta.xml b/examples/translation/force-app/objects/Event__c/fields/Tag_Line__c.field-meta.xml new file mode 100644 index 00000000..652ee2e0 --- /dev/null +++ b/examples/translation/force-app/objects/Event__c/fields/Tag_Line__c.field-meta.xml @@ -0,0 +1,11 @@ + + + Tag_Line__c + false + + 255 + false + false + Text + false + diff --git a/examples/translation/force-app/objects/Price_Component__c/Price_Component__c.object-meta.xml b/examples/translation/force-app/objects/Price_Component__c/Price_Component__c.object-meta.xml new file mode 100644 index 00000000..ae72fd0c --- /dev/null +++ b/examples/translation/force-app/objects/Price_Component__c/Price_Component__c.object-meta.xml @@ -0,0 +1,169 @@ + + + + Accept + Default + + + Accept + Large + Default + + + Accept + Small + Default + + + CancelEdit + Default + + + CancelEdit + Large + Default + + + CancelEdit + Small + Default + + + Clone + Default + + + Clone + Large + Default + + + Clone + Small + Default + + + Delete + Default + + + Delete + Large + Default + + + Delete + Small + Default + + + Edit + Default + + + Edit + Large + Default + + + Edit + Small + Default + + + List + Default + + + List + Large + Default + + + List + Small + Default + + + New + Default + + + New + Large + Default + + + New + Small + Default + + + SaveEdit + Default + + + SaveEdit + Large + Default + + + SaveEdit + Small + Default + + + Tab + Default + + + Tab + Large + Default + + + Tab + Small + Default + + + View + Action override created by Lightning App Builder during activation. + Price_Component_Record_Page + Large + false + Flexipage + + + View + Default + + + View + Small + Default + + false + SYSTEM + Deployed + false + true + false + false + false + false + false + true + true + Private + + + PC-{0000} + + AutoNumber + + Price Components + + ReadWrite + Public + diff --git a/examples/translation/force-app/objects/Price_Component__c/fields/Description__c.field-meta.xml b/examples/translation/force-app/objects/Price_Component__c/fields/Description__c.field-meta.xml new file mode 100644 index 00000000..69050ca6 --- /dev/null +++ b/examples/translation/force-app/objects/Price_Component__c/fields/Description__c.field-meta.xml @@ -0,0 +1,11 @@ + + + Description__c + false + + 255 + false + false + Text + false + diff --git a/examples/translation/force-app/objects/Price_Component__c/fields/Expression__c.field-meta.xml b/examples/translation/force-app/objects/Price_Component__c/fields/Expression__c.field-meta.xml new file mode 100644 index 00000000..c0bf4e45 --- /dev/null +++ b/examples/translation/force-app/objects/Price_Component__c/fields/Expression__c.field-meta.xml @@ -0,0 +1,12 @@ + + + Expression__c + The Expression that determines if this price should take effect or not. + false + The Expression that determines if this price should take effect or not. + + 131072 + false + LongTextArea + 20 + diff --git a/examples/translation/force-app/objects/Price_Component__c/fields/Percent__c.field-meta.xml b/examples/translation/force-app/objects/Price_Component__c/fields/Percent__c.field-meta.xml new file mode 100644 index 00000000..9c303bc4 --- /dev/null +++ b/examples/translation/force-app/objects/Price_Component__c/fields/Percent__c.field-meta.xml @@ -0,0 +1,13 @@ + + + Percent__c + Use this field to calculate the price based on the list price's percentage instead of providing a flat price. + false + Use this field to calculate the price based on the list price's percentage instead of providing a flat price. + + 18 + false + 0 + false + Percent + diff --git a/examples/translation/force-app/objects/Price_Component__c/fields/Price__c.field-meta.xml b/examples/translation/force-app/objects/Price_Component__c/fields/Price__c.field-meta.xml new file mode 100644 index 00000000..84136dec --- /dev/null +++ b/examples/translation/force-app/objects/Price_Component__c/fields/Price__c.field-meta.xml @@ -0,0 +1,13 @@ + + + Price__c + Use this when the Price Component represents a Flat Price. To represent a Percentage use the Percent field. + false + Use this when the Price Component represents a Flat Price. To represent a Percentage use the Percent field. + + 18 + false + 2 + false + Currency + diff --git a/examples/translation/force-app/objects/Price_Component__c/fields/Type__c.field-meta.xml b/examples/translation/force-app/objects/Price_Component__c/fields/Type__c.field-meta.xml new file mode 100644 index 00000000..c430b305 --- /dev/null +++ b/examples/translation/force-app/objects/Price_Component__c/fields/Type__c.field-meta.xml @@ -0,0 +1,30 @@ + + + Type__c + false + + true + false + Picklist + + true + + false + + List Price + false + + + + Surcharge + false + + + + Discount + false + + + + + diff --git a/examples/translation/force-app/objects/Product_Price_Component__c/Product_Price_Component__c.object-meta.xml b/examples/translation/force-app/objects/Product_Price_Component__c/Product_Price_Component__c.object-meta.xml new file mode 100644 index 00000000..8a9a6348 --- /dev/null +++ b/examples/translation/force-app/objects/Product_Price_Component__c/Product_Price_Component__c.object-meta.xml @@ -0,0 +1,166 @@ + + + + Accept + Default + + + Accept + Large + Default + + + Accept + Small + Default + + + CancelEdit + Default + + + CancelEdit + Large + Default + + + CancelEdit + Small + Default + + + Clone + Default + + + Clone + Large + Default + + + Clone + Small + Default + + + Delete + Default + + + Delete + Large + Default + + + Delete + Small + Default + + + Edit + Default + + + Edit + Large + Default + + + Edit + Small + Default + + + List + Default + + + List + Large + Default + + + List + Small + Default + + + New + Default + + + New + Large + Default + + + New + Small + Default + + + SaveEdit + Default + + + SaveEdit + Large + Default + + + SaveEdit + Small + Default + + + Tab + Default + + + Tab + Large + Default + + + Tab + Small + Default + + + View + Default + + + View + Large + Default + + + View + Small + Default + + false + SYSTEM + Deployed + false + true + false + false + false + false + false + true + true + ControlledByParent + + + PPC-{0000} + + AutoNumber + + Product Price Components + + ControlledByParent + Public + diff --git a/examples/translation/force-app/objects/Product_Price_Component__c/fields/Price_Component__c.field-meta.xml b/examples/translation/force-app/objects/Product_Price_Component__c/fields/Price_Component__c.field-meta.xml new file mode 100644 index 00000000..f152ecb6 --- /dev/null +++ b/examples/translation/force-app/objects/Product_Price_Component__c/fields/Price_Component__c.field-meta.xml @@ -0,0 +1,14 @@ + + + Price_Component__c + false + + Price_Component__c + Product Price Components + Product_Price_Components + 1 + false + false + MasterDetail + false + diff --git a/examples/translation/force-app/objects/Product_Price_Component__c/fields/Product__c.field-meta.xml b/examples/translation/force-app/objects/Product_Price_Component__c/fields/Product__c.field-meta.xml new file mode 100644 index 00000000..16ec5b33 --- /dev/null +++ b/examples/translation/force-app/objects/Product_Price_Component__c/fields/Product__c.field-meta.xml @@ -0,0 +1,14 @@ + + + Product__c + false + + Product__c + Product Price Components + Product_Price_Components + 0 + false + false + MasterDetail + false + diff --git a/examples/translation/force-app/objects/Product__c/Product__c.object-meta.xml b/examples/translation/force-app/objects/Product__c/Product__c.object-meta.xml new file mode 100644 index 00000000..cdeb52a9 --- /dev/null +++ b/examples/translation/force-app/objects/Product__c/Product__c.object-meta.xml @@ -0,0 +1,169 @@ + + + + Accept + Default + + + Accept + Large + Default + + + Accept + Small + Default + + + CancelEdit + Default + + + CancelEdit + Large + Default + + + CancelEdit + Small + Default + + + Clone + Default + + + Clone + Large + Default + + + Clone + Small + Default + + + Delete + Default + + + Delete + Large + Default + + + Delete + Small + Default + + + Edit + Default + + + Edit + Large + Default + + + Edit + Small + Default + + + List + Default + + + List + Large + Default + + + List + Small + Default + + + New + Default + + + New + Large + Default + + + New + Small + Default + + + SaveEdit + Default + + + SaveEdit + Large + Default + + + SaveEdit + Small + Default + + + Tab + Default + + + Tab + Large + Default + + + Tab + Small + Default + + + View + Action override created by Lightning App Builder during activation. + Product_Record_Page + Large + false + Flexipage + + + View + Default + + + View + Small + Default + + false + SYSTEM + Deployed + false + true + false + false + false + false + false + true + true + Private + + Product that is sold or available for sale. + + + Text + + Products + + ReadWrite + Public + diff --git a/examples/translation/force-app/objects/Product__c/fields/Description__c.field-meta.xml b/examples/translation/force-app/objects/Product__c/fields/Description__c.field-meta.xml new file mode 100644 index 00000000..69050ca6 --- /dev/null +++ b/examples/translation/force-app/objects/Product__c/fields/Description__c.field-meta.xml @@ -0,0 +1,11 @@ + + + Description__c + false + + 255 + false + false + Text + false + diff --git a/examples/translation/force-app/objects/Product__c/fields/Event__c.field-meta.xml b/examples/translation/force-app/objects/Product__c/fields/Event__c.field-meta.xml new file mode 100644 index 00000000..82947d0b --- /dev/null +++ b/examples/translation/force-app/objects/Product__c/fields/Event__c.field-meta.xml @@ -0,0 +1,12 @@ + + + Event__c + Restrict + false + + Event__c + Products + true + false + Lookup + diff --git a/examples/translation/force-app/objects/Product__c/fields/Features__c.field-meta.xml b/examples/translation/force-app/objects/Product__c/fields/Features__c.field-meta.xml new file mode 100644 index 00000000..6b67a859 --- /dev/null +++ b/examples/translation/force-app/objects/Product__c/fields/Features__c.field-meta.xml @@ -0,0 +1,10 @@ + + + Features__c + false + + 32768 + false + LongTextArea + 10 + diff --git a/examples/translation/force-app/objects/Sales_Order_Line__c/Sales_Order_Line__c.object-meta.xml b/examples/translation/force-app/objects/Sales_Order_Line__c/Sales_Order_Line__c.object-meta.xml new file mode 100644 index 00000000..36e9348d --- /dev/null +++ b/examples/translation/force-app/objects/Sales_Order_Line__c/Sales_Order_Line__c.object-meta.xml @@ -0,0 +1,167 @@ + + + + Accept + Default + + + Accept + Large + Default + + + Accept + Small + Default + + + CancelEdit + Default + + + CancelEdit + Large + Default + + + CancelEdit + Small + Default + + + Clone + Default + + + Clone + Large + Default + + + Clone + Small + Default + + + Delete + Default + + + Delete + Large + Default + + + Delete + Small + Default + + + Edit + Default + + + Edit + Large + Default + + + Edit + Small + Default + + + List + Default + + + List + Large + Default + + + List + Small + Default + + + New + Default + + + New + Large + Default + + + New + Small + Default + + + SaveEdit + Default + + + SaveEdit + Large + Default + + + SaveEdit + Small + Default + + + Tab + Default + + + Tab + Large + Default + + + Tab + Small + Default + + + View + Default + + + View + Large + Default + + + View + Small + Default + + false + SYSTEM + Deployed + false + true + false + false + false + false + false + true + true + ControlledByParent + + Represents a line item on a sales order. + + SOL-{0000} + + AutoNumber + + Sales Order Lines + + ControlledByParent + Public + diff --git a/examples/translation/force-app/objects/Sales_Order_Line__c/fields/Amount__c.field-meta.xml b/examples/translation/force-app/objects/Sales_Order_Line__c/fields/Amount__c.field-meta.xml new file mode 100644 index 00000000..3a464e2d --- /dev/null +++ b/examples/translation/force-app/objects/Sales_Order_Line__c/fields/Amount__c.field-meta.xml @@ -0,0 +1,11 @@ + + + Amount__c + false + + 18 + true + 2 + false + Currency + diff --git a/examples/translation/force-app/objects/Sales_Order_Line__c/fields/Product__c.field-meta.xml b/examples/translation/force-app/objects/Sales_Order_Line__c/fields/Product__c.field-meta.xml new file mode 100644 index 00000000..b6b5369f --- /dev/null +++ b/examples/translation/force-app/objects/Sales_Order_Line__c/fields/Product__c.field-meta.xml @@ -0,0 +1,13 @@ + + + Product__c + Restrict + false + + Product__c + Sales Order Lines + Sales_Order_Lines + true + false + Lookup + diff --git a/examples/translation/force-app/objects/Sales_Order_Line__c/fields/Sales_Order__c.field-meta.xml b/examples/translation/force-app/objects/Sales_Order_Line__c/fields/Sales_Order__c.field-meta.xml new file mode 100644 index 00000000..c1d881c8 --- /dev/null +++ b/examples/translation/force-app/objects/Sales_Order_Line__c/fields/Sales_Order__c.field-meta.xml @@ -0,0 +1,14 @@ + + + Sales_Order__c + false + + Sales_Order__c + Sales Order Lines + Sales_Order_Lines + 0 + false + false + MasterDetail + false + diff --git a/examples/translation/force-app/objects/Sales_Order_Line__c/fields/Source_Price_Component__c.field-meta.xml b/examples/translation/force-app/objects/Sales_Order_Line__c/fields/Source_Price_Component__c.field-meta.xml new file mode 100644 index 00000000..69817d96 --- /dev/null +++ b/examples/translation/force-app/objects/Sales_Order_Line__c/fields/Source_Price_Component__c.field-meta.xml @@ -0,0 +1,13 @@ + + + Source_Price_Component__c + SetNull + false + + Price_Component__c + Sales Order Lines + Sales_Order_Lines + false + false + Lookup + diff --git a/examples/translation/force-app/objects/Sales_Order_Line__c/fields/Type__c.field-meta.xml b/examples/translation/force-app/objects/Sales_Order_Line__c/fields/Type__c.field-meta.xml new file mode 100644 index 00000000..328b5529 --- /dev/null +++ b/examples/translation/force-app/objects/Sales_Order_Line__c/fields/Type__c.field-meta.xml @@ -0,0 +1,26 @@ + + + Type__c + "Charge" + false + + true + false + Picklist + + true + + false + + Charge + false + + + + Discount + false + + + + + diff --git a/examples/translation/force-app/objects/Sales_Order__c/Sales_Order__c.object-meta.xml b/examples/translation/force-app/objects/Sales_Order__c/Sales_Order__c.object-meta.xml new file mode 100644 index 00000000..2225e4f9 --- /dev/null +++ b/examples/translation/force-app/objects/Sales_Order__c/Sales_Order__c.object-meta.xml @@ -0,0 +1,170 @@ + + + + Accept + Default + + + Accept + Large + Default + + + Accept + Small + Default + + + CancelEdit + Default + + + CancelEdit + Large + Default + + + CancelEdit + Small + Default + + + Clone + Default + + + Clone + Large + Default + + + Clone + Small + Default + + + Delete + Default + + + Delete + Large + Default + + + Delete + Small + Default + + + Edit + Default + + + Edit + Large + Default + + + Edit + Small + Default + + + List + Default + + + List + Large + Default + + + List + Small + Default + + + New + Default + + + New + Large + Default + + + New + Small + Default + + + SaveEdit + Default + + + SaveEdit + Large + Default + + + SaveEdit + Small + Default + + + Tab + Default + + + Tab + Large + Default + + + Tab + Small + Default + + + View + Action override created by Lightning App Builder during activation. + Sales_Order_Record_Page + Large + false + Flexipage + + + View + Default + + + View + Small + Default + + false + SYSTEM + Deployed + false + true + false + false + false + false + false + true + true + Private + + Custom object for tracking sales orders. + + SO-{0000} + + AutoNumber + + Sales Orders + + ReadWrite + Public + diff --git a/examples/translation/force-app/objects/Speaker__c/Speaker__c.object-meta.xml b/examples/translation/force-app/objects/Speaker__c/Speaker__c.object-meta.xml new file mode 100644 index 00000000..6bdf2199 --- /dev/null +++ b/examples/translation/force-app/objects/Speaker__c/Speaker__c.object-meta.xml @@ -0,0 +1,167 @@ + + + + Accept + Default + + + Accept + Large + Default + + + Accept + Small + Default + + + CancelEdit + Default + + + CancelEdit + Large + Default + + + CancelEdit + Small + Default + + + Clone + Default + + + Clone + Large + Default + + + Clone + Small + Default + + + Delete + Default + + + Delete + Large + Default + + + Delete + Small + Default + + + Edit + Default + + + Edit + Large + Default + + + Edit + Small + Default + + + List + Default + + + List + Large + Default + + + List + Small + Default + + + New + Default + + + New + Large + Default + + + New + Small + Default + + + SaveEdit + Default + + + SaveEdit + Large + Default + + + SaveEdit + Small + Default + + + Tab + Default + + + Tab + Large + Default + + + Tab + Small + Default + + + View + Default + + + View + Large + Default + + + View + Small + Default + + false + SYSTEM + Deployed + false + true + false + false + false + false + false + true + true + ControlledByParent + + Represents a speaker at an event. + + SPEAK-{0000} + + AutoNumber + + Speakers + + ControlledByParent + Public + diff --git a/examples/translation/force-app/objects/Speaker__c/fields/About__c.field-meta.xml b/examples/translation/force-app/objects/Speaker__c/fields/About__c.field-meta.xml new file mode 100644 index 00000000..2fc71d94 --- /dev/null +++ b/examples/translation/force-app/objects/Speaker__c/fields/About__c.field-meta.xml @@ -0,0 +1,10 @@ + + + About__c + false + + 32768 + false + LongTextArea + 3 + diff --git a/examples/translation/force-app/objects/Speaker__c/fields/Event__c.field-meta.xml b/examples/translation/force-app/objects/Speaker__c/fields/Event__c.field-meta.xml new file mode 100644 index 00000000..cf6bfc63 --- /dev/null +++ b/examples/translation/force-app/objects/Speaker__c/fields/Event__c.field-meta.xml @@ -0,0 +1,14 @@ + + + Event__c + false + + Event__c + Speakers + Speakers + 0 + false + false + MasterDetail + false + diff --git a/examples/translation/force-app/objects/Speaker__c/fields/Person__c.field-meta.xml b/examples/translation/force-app/objects/Speaker__c/fields/Person__c.field-meta.xml new file mode 100644 index 00000000..b7ac07b1 --- /dev/null +++ b/examples/translation/force-app/objects/Speaker__c/fields/Person__c.field-meta.xml @@ -0,0 +1,14 @@ + + + Person__c + false + + Contact + Speakers + Speakers + 1 + false + false + MasterDetail + false + diff --git a/examples/translation/package-lock.json b/examples/translation/package-lock.json new file mode 100644 index 00000000..04522b29 --- /dev/null +++ b/examples/translation/package-lock.json @@ -0,0 +1,724 @@ +{ + "name": "plain-markdown", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "plain-markdown", + "dependencies": { + "rimraf": "^5.0.7" + }, + "devDependencies": { + "ts-node": "^10.9.2" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "24.0.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.0.7.tgz", + "integrity": "sha512-YIEUUr4yf8q8oQoXPpSlnvKNVKDQlPMWrmOcgzoduo7kvA2UF0/BwJ/eMKFTiTtkNL17I0M6Xe2tvwFU7be6iw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "undici-types": "~7.8.0" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "license": "MIT" + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "license": "BlueOak-1.0.0" + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/rimraf": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.10.tgz", + "integrity": "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==", + "license": "ISC", + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.8.0.tgz", + "integrity": "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "license": "MIT" + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + } + } +} diff --git a/examples/translation/package.json b/examples/translation/package.json new file mode 100644 index 00000000..9accabc8 --- /dev/null +++ b/examples/translation/package.json @@ -0,0 +1,15 @@ +{ + "name": "plain-markdown", + "scripts": { + "docs:clean": "rimraf docs", + "docs:build": "ts-node ../../src/cli/generate.ts markdown", + "docs:help": "ts-node ../../src/cli/generate.ts markdown --help", + "docs:gen": "npm run docs:clean && npm run docs:build" + }, + "devDependencies": { + "ts-node": "^10.9.2" + }, + "dependencies": { + "rimraf": "^5.0.7" + } +} diff --git a/examples/translation/sfdx-project.json b/examples/translation/sfdx-project.json new file mode 100644 index 00000000..ceefdfd9 --- /dev/null +++ b/examples/translation/sfdx-project.json @@ -0,0 +1,12 @@ +{ + "packageDirectories": [ + { + "path": "force-app", + "default": true + } + ], + "name": "plain-markdown", + "namespace": "", + "sfdcLoginUrl": "https://login.salesforce.com", + "sourceApiVersion": "59.0" +} diff --git a/src/core/markdown/adapters/renderable-to-page-data.ts b/src/core/markdown/adapters/renderable-to-page-data.ts index b1cc878e..5a0cb008 100644 --- a/src/core/markdown/adapters/renderable-to-page-data.ts +++ b/src/core/markdown/adapters/renderable-to-page-data.ts @@ -101,7 +101,7 @@ function resolveApexTypeTemplate(renderable: Renderable, translations: Translati return { template: getTemplate(renderable), source: { - ...(renderable as RenderableEnum), + ...renderable, translations, }, }; diff --git a/src/core/markdown/templates/class-template.ts b/src/core/markdown/templates/class-template.ts index 276beec0..e9c2f9d9 100644 --- a/src/core/markdown/templates/class-template.ts +++ b/src/core/markdown/templates/class-template.ts @@ -7,13 +7,13 @@ export const classMarkdownTemplate = ` {{> typeDocumentation}} {{#if extends.length}} -**{{#if translations.markdown.inheritance.inheritance}}{{translations.markdown.inheritance.inheritance}}{{else}}Inheritance{{/if}}** +**{{@root.translations.markdown.inheritance.inheritance}}** {{#each extends}}{{link this}}{{#unless @last}} < {{/unless}}{{/each}} {{/if}} {{#if implements}} -**{{#if translations.markdown.inheritance.implements}}{{translations.markdown.inheritance.implements}}{{else}}Implements{{/if}}** +**{{@root.translations.markdown.inheritance.implements}}** {{#each implements}} {{link this}}{{#unless @last}}, {{/unless}} diff --git a/src/core/markdown/templates/custom-object-template.ts b/src/core/markdown/templates/custom-object-template.ts index cf85d297..8a02390d 100644 --- a/src/core/markdown/templates/custom-object-template.ts +++ b/src/core/markdown/templates/custom-object-template.ts @@ -3,11 +3,11 @@ export const customObjectTemplate = ` {{{renderContent doc.description}}} -## {{#if translations.markdown.details.apiName}}{{translations.markdown.details.apiName}}{{else}}API Name{{/if}} +## {{@root.translations.markdown.details.apiName}} \`{{apiName}}\` {{#if publishBehavior}} -## {{#if translations.markdown.sections.publishBehavior}}{{translations.markdown.sections.publishBehavior}}{{else}}Publish Behavior{{/if}} +## {{@root.translations.markdown.sections.publishBehavior}} **{{publishBehavior}}** {{/if}} @@ -17,7 +17,7 @@ export const customObjectTemplate = ` {{#each fields.value}} {{ heading headingLevel heading }} {{#if required}} -**{{#if translations.markdown.details.required}}{{translations.markdown.details.required}}{{else}}Required{{/if}}** +**{{@root.translations.markdown.details.required}}** {{/if}} {{#if description}} @@ -25,26 +25,26 @@ export const customObjectTemplate = ` {{/if}} {{#if inlineHelpText}} -**{{#if translations.markdown.details.inlineHelpText}}{{translations.markdown.details.inlineHelpText}}{{else}}Inline Help Text{{/if}}** +**{{@root.translations.markdown.details.inlineHelpText}}** {{inlineHelpText}} {{/if}} {{#if complianceGroup}} -**{{#if translations.markdown.details.complianceGroup}}{{translations.markdown.details.complianceGroup}}{{else}}Compliance Group{{/if}}** +**{{@root.translations.markdown.details.complianceGroup}}** {{complianceGroup}} {{/if}} {{#if securityClassification}} -**{{#if translations.markdown.details.securityClassification}}{{translations.markdown.details.securityClassification}}{{else}}Security Classification{{/if}}** +**{{@root.translations.markdown.details.securityClassification}}** {{securityClassification}} {{/if}} -**{{#if translations.markdown.details.apiName}}{{translations.markdown.details.apiName}}{{else}}API Name{{/if}}** +**{{@root.translations.markdown.details.apiName}}** \`{{{apiName}}}\` {{#if fieldType}} -**{{#if translations.markdown.details.type}}{{translations.markdown.details.type}}{{else}}Type{{/if}}** +**{{@root.translations.markdown.details.type}}** *{{fieldType}}* @@ -66,14 +66,14 @@ export const customObjectTemplate = ` {{ heading headingLevel heading }} {{#if protected}} -\`{{#if translations.markdown.details.protected}}{{translations.markdown.details.protected}}{{else}}Protected{{/if}}\` +\`{{@root.translations.markdown.details.protected}}\` {{/if}} {{#if description}} {{{renderContent description}}} {{/if}} -**{{#if translations.markdown.details.apiName}}{{translations.markdown.details.apiName}}{{else}}API Name{{/if}}** +**{{@root.translations.markdown.details.apiName}}** \`{{{apiName}}}\` diff --git a/src/core/markdown/templates/type-doc-partial.ts b/src/core/markdown/templates/type-doc-partial.ts index df1c4c61..8bb42d0f 100644 --- a/src/core/markdown/templates/type-doc-partial.ts +++ b/src/core/markdown/templates/type-doc-partial.ts @@ -1,25 +1,27 @@ export const typeDocPartial = ` {{#> documentablePartialTemplate}} + + {{#if doc.group}} -**{{#if translations.markdown.details.group}}{{translations.markdown.details.group}}{{else}}Group{{/if}}** {{doc.group}} +**{{@root.translations.markdown.details.group}}** {{doc.group}} {{/if}} {{#if doc.author}} -**{{#if translations.markdown.details.author}}{{translations.markdown.details.author}}{{else}}Author{{/if}}** {{doc.author}} +**{{@root.translations.markdown.details.author}}** {{doc.author}} {{/if}} {{#if doc.date}} -**{{#if translations.markdown.details.date}}{{translations.markdown.details.date}}{{else}}Date{{/if}}** {{doc.date}} +**{{@root.translations.markdown.details.date}}** {{doc.date}} {{/if}} {{#each doc.sees}} -**{{#if ../translations.markdown.details.see}}{{../translations.markdown.details.see}}{{else}}See{{/if}}** {{link this}} +**{{@root.translations.markdown.details.see}}** {{link this}} {{/each}} {{#if namespace}} -## {{#if translations.markdown.sections.namespace}}{{translations.markdown.sections.namespace}}{{else}}Namespace{{/if}} +## {{@root.translations.markdown.sections.namespace}} {{namespace}} {{/if}} From 6f248a00ac0cb6fdacc1e03bb1209162cca46ae0 Mon Sep 17 00:00:00 2001 From: cesarParra Date: Sun, 29 Jun 2025 09:25:11 -0400 Subject: [PATCH 3/6] Add Spanish translations and example metadata for documentation generation --- examples/translation-example/README.md | 267 ------------------------- examples/translation/README.md | 64 ++++++ 2 files changed, 64 insertions(+), 267 deletions(-) delete mode 100644 examples/translation-example/README.md create mode 100644 examples/translation/README.md diff --git a/examples/translation-example/README.md b/examples/translation-example/README.md deleted file mode 100644 index 036049d7..00000000 --- a/examples/translation-example/README.md +++ /dev/null @@ -1,267 +0,0 @@ -# Sample Project With Provided Translations - -Demonstrates how to provide translations to ApexDocs to customize the language and terminology used in generated documentation. - -## Overview - -The translation feature allows you to: - -1. **Translate documentation to different languages** (Spanish, French, etc.) -2. **Use custom business terminology** (e.g., "Business Operations" instead of "Methods") -3. **Partially override specific terms** while keeping the rest in English -4. **Maintain consistency** across your organization's documentation standards - -## How It Works - -ApexDocs uses a translation system with: - -- **Default English translations** built into the system -- **User-provided overrides** that can be partial or complete -- **Deep merging** so you only need to specify what you want to change - -## Configuration - -Add a `translations` property to your ApexDocs configuration: - -```javascript -import { defineMarkdownConfig } from '@cparra/apexdocs'; - -export default defineMarkdownConfig({ - sourceDir: 'src', - targetDir: 'docs', - scope: ['public', 'global'], - translations: { - // Your custom translations here - markdown: { - sections: { - methods: 'Métodos', - properties: 'Propiedades', - fields: 'Campos', - }, - }, - }, -}); -``` - -## Translation Structure - -The translation object has two main sections: - -### Changelog Translations - -```javascript -{ - changelog: { - title: 'Changelog', - newClasses: { - heading: 'New Classes', - description: 'These classes are new.', - }, - newInterfaces: { - heading: 'New Interfaces', - description: 'These interfaces are new.', - }, - // ... more changelog sections - memberModifications: { - newMethod: 'New Method', - removedMethod: 'Removed Method', - // ... more modification types - }, - } -} -``` - -### Markdown Documentation Translations - -```javascript -{ - markdown: { - sections: { - methods: 'Methods', - properties: 'Properties', - fields: 'Fields', - constructors: 'Constructors', - values: 'Values', // for enums - classes: 'Classes', // for inner classes - enums: 'Enums', // for inner enums - interfaces: 'Interfaces', // for inner interfaces - namespace: 'Namespace', - records: 'Records', // for custom metadata - publishBehavior: 'Publish Behavior', - }, - details: { - type: 'Type', - signature: 'Signature', - group: 'Group', - author: 'Author', - date: 'Date', - see: 'See', - possibleValues: 'Possible values are', - parameters: 'Parameters', - throws: 'Throws', - returnType: 'Return Type', - apiName: 'API Name', - required: 'Required', - // ... more detail labels - }, - typeSuffixes: { - class: 'Class', - interface: 'Interface', - enum: 'Enum', - trigger: 'Trigger', - }, - triggerEvents: { - beforeInsert: 'Before Insert', - beforeUpdate: 'Before Update', - // ... more trigger events - }, - publishBehaviors: { - publishImmediately: 'Publish Immediately', - publishAfterCommit: 'Publish After Commit', - }, - inheritance: { - inheritance: 'Inheritance', - implements: 'Implements', - }, - } -} -``` - -## Examples - -### Complete Spanish Translation - -```javascript -const spanishTranslations = { - changelog: { - title: 'Registro de Cambios', - newClasses: { - heading: 'Nuevas Clases', - description: 'Estas clases son nuevas.', - }, - // ... more changelog translations - }, - markdown: { - sections: { - methods: 'Métodos', - properties: 'Propiedades', - fields: 'Campos', - constructors: 'Constructores', - }, - details: { - type: 'Tipo', - signature: 'Firma', - parameters: 'Parámetros', - }, - typeSuffixes: { - class: 'Clase', - interface: 'Interfaz', - enum: 'Enum', - }, - }, -}; -``` - -### Custom Business Terminology - -```javascript -const businessTerminology = { - markdown: { - sections: { - methods: 'Business Operations', - properties: 'Business Attributes', - fields: 'Data Elements', - constructors: 'Initializers', - }, - typeSuffixes: { - class: 'Service', - interface: 'Contract', - }, - }, -}; -``` - -### Partial Overrides - -```javascript -const partialTranslations = { - markdown: { - sections: { - methods: 'Functions', // Only change "Methods" to "Functions" - }, - }, -}; -``` - -## Usage with Different Generators - -### Markdown Generator - -```javascript -export default defineMarkdownConfig({ - sourceDir: 'src', - targetDir: 'docs', - scope: ['public', 'global'], - translations: yourTranslations, -}); -``` - -### Changelog Generator - -```javascript -export default defineChangelogConfig({ - previousVersionDir: 'previous', - currentVersionDir: 'current', - targetDir: 'changelog', - fileName: 'CHANGELOG', - scope: ['public', 'global'], - translations: yourTranslations, -}); -``` - -## Best Practices - -1. **Start Small**: Begin with partial translations for the most important terms -2. **Be Consistent**: Use the same terminology across your organization -3. **Test Thoroughly**: Generate documentation with your translations to verify the output -4. **Document Your Choices**: Keep track of your translation decisions for future reference -5. **Version Control**: Include your translation configurations in version control - -## TypeScript Support - -If you're using TypeScript, you can import the translation types for better autocomplete and type safety: - -```typescript -import { defineMarkdownConfig } from '@cparra/apexdocs'; -import type { UserTranslations } from '@cparra/apexdocs'; - -const translations: UserTranslations = { - markdown: { - sections: { - methods: 'Functions', - }, - }, -}; - -export default defineMarkdownConfig({ - sourceDir: 'src', - targetDir: 'docs', - scope: ['public', 'global'], - translations, -}); -``` - -## Validation - -The translation system includes basic validation to catch common mistakes: - -- Invalid top-level keys will generate warnings -- Missing translations fall back to English defaults -- Deep merging ensures you only need to specify what changes - -## Notes - -- Only the **markdown** and **changelog** generators support translations -- The **OpenAPI** generator does not use the translation system -- All translations are optional - anything not specified uses the English default -- The system uses deep merging, so partial translations work seamlessly diff --git a/examples/translation/README.md b/examples/translation/README.md new file mode 100644 index 00000000..4e5539ed --- /dev/null +++ b/examples/translation/README.md @@ -0,0 +1,64 @@ +# Sample Project With Provided Translations + +Demonstrates how to provide translations to ApexDocs to customize the language and terminology used in generated documentation. + +## Overview + +The translation feature allows you to: + +1. **Translate documentation to different languages** (Spanish, French, etc.) +2. **Use custom business terminology** (e.g., "Business Operations" instead of "Methods") +3. **Partially override specific terms** while keeping the rest in English + +## Configuration + +Add a `translations` property to your ApexDocs configuration: + +```javascript +import { defineMarkdownConfig } from '@cparra/apexdocs'; + +export default defineMarkdownConfig({ + sourceDir: 'src', + targetDir: 'docs', + scope: ['public', 'global'], + translations: { + // Your custom translations here + markdown: { + sections: { + methods: 'Métodos', + properties: 'Propiedades', + fields: 'Campos', + }, + }, + }, +}); +``` + +## TypeScript Support + +If you're using TypeScript, you can import the translation types for better autocomplete and type safety: + +```typescript +import { defineMarkdownConfig } from '@cparra/apexdocs'; +import type { UserTranslations } from '@cparra/apexdocs'; + +const translations: UserTranslations = { + markdown: { + sections: { + methods: 'Functions', + }, + }, +}; + +export default defineMarkdownConfig({ + sourceDir: 'src', + targetDir: 'docs', + scope: ['public', 'global'], + translations, +}); +``` + +## Notes + +- Only the **markdown** and **changelog** generators support translations +- All translations are optional - anything not specified uses the English default From 3c1cf0977950968e5a4a8bc8cc4f2dc6c6fd9fe3 Mon Sep 17 00:00:00 2001 From: cesarParra Date: Sun, 29 Jun 2025 09:46:09 -0400 Subject: [PATCH 4/6] Refine translation config typing and usage for markdown and changelog generators --- README.md | 45 +++++--------- examples/translation/apexdocs.config.ts | 58 +++++++++---------- src/core/changelog/generate-change-log.ts | 2 +- .../adapters/renderable-to-page-data.ts | 2 +- src/core/markdown/generate-docs.ts | 2 +- src/core/shared/types.d.ts | 4 +- 6 files changed, 48 insertions(+), 65 deletions(-) diff --git a/README.md b/README.md index ae5b3d89..08d11f6c 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ create a documentation site that fits your needs, hosted in any static web hosti - [OpenApi](#openapi-1) - [Changelog](#changelog-1) - [🔬 Defining a configuration file](#-defining-a-configuration-file) -- [🌐 Translation](#-translation-support) +- [🌐 Translation](#-translation) - [⤵︎ Importing to your project](#︎-importing-to-your-project) - [📖 Documentation Guide](#-documentation-guide) - [📄 Generating OpenApi REST Definitions](#-generating-openapi-rest-definitions) @@ -296,11 +296,9 @@ export default defineMarkdownConfig({ targetDir: 'docs', scope: ['global', 'public'], translations: { - markdown: { - sections: { - methods: 'Methods', - properties: 'Properties', - }, + sections: { + methods: 'Methods', + properties: 'Properties', }, }, ... @@ -633,8 +631,6 @@ This feature allows you to: - **Use custom business terminology** (e.g., "Business Operations" instead of "Methods") - **Partially override specific terms** while keeping the rest in English -Translation is supported for the `markdown` and `changelog` generators. - ### How It Works The translation system uses: @@ -644,7 +640,8 @@ The translation system uses: ### Configuration -Add a `translations` property to your ApexDocs configuration (JS or TS file): +Add a `translations` property to your ApexDocs configuration (JS or TS file) and pass +the appropriate translation object, depending on the generator you're using: ```javascript import { defineMarkdownConfig } from '@cparra/apexdocs'; @@ -654,12 +651,10 @@ export default defineMarkdownConfig({ targetDir: 'docs', scope: ['public', 'global'], translations: { - markdown: { - sections: { - methods: 'Métodos', - properties: 'Propiedades', - fields: 'Campos', - }, + sections: { + methods: 'Métodos', + properties: 'Propiedades', + fields: 'Campos', }, }, }); @@ -673,35 +668,25 @@ For TypeScript projects, import the translation types for better autocomplete an import { defineMarkdownConfig } from '@cparra/apexdocs'; import type { UserTranslations } from '@cparra/apexdocs'; -const translations: UserTranslations = { - markdown: { - sections: { - methods: 'Functions', - }, +const markdownTranslations: UserTranslations['markdown'] = { + sections: { + methods: 'Functions', }, + // ...other translation keys as needed }; export default defineMarkdownConfig({ sourceDir: 'src', targetDir: 'docs', scope: ['public', 'global'], - translations, + translations: markdownTranslations, }); ``` -### Best Practices - -1. **Start Small**: Begin with partial translations for the most important terms -2. **Be Consistent**: Use the same terminology across your organization -3. **Test Thoroughly**: Generate documentation with your translations to verify the output -4. **Version Control**: Include your translation configurations in version control - ### Notes - Only the **markdown** and **changelog** generators support translations -- The **OpenAPI** generator does not use the translation system - All translations are optional - anything not specified uses the English default -- The system uses deep merging, so partial translations work seamlessly For a complete example, see the [translation example](examples/translation/) in this repository. diff --git a/examples/translation/apexdocs.config.ts b/examples/translation/apexdocs.config.ts index bb79d2ec..bdb4bcab 100644 --- a/examples/translation/apexdocs.config.ts +++ b/examples/translation/apexdocs.config.ts @@ -1,36 +1,34 @@ import { defineMarkdownConfig, UserTranslations } from '../../src'; // Spanish translations -const spanishTranslations: UserTranslations = { - markdown: { - sections: { - methods: 'Métodos', - properties: 'Propiedades', - fields: 'Campos', - constructors: 'Constructores', - namespace: 'Espacio de Nombres', - values: 'Valores', - }, - details: { - apiName: 'Nombre API', - type: 'Tipo', - signature: 'Firma', - parameters: 'Parámetros', - returnType: 'Tipo de Retorno', - throws: 'Lanza', - required: 'Requerido', - author: 'Autor', - }, - typeSuffixes: { - class: 'Clase', - interface: 'Interfaz', - enum: 'Enum', - trigger: 'Disparador', - }, - inheritance: { - inheritance: 'Herencia', - implements: 'Implementa', - }, +const spanishTranslations: UserTranslations['markdown'] = { + sections: { + methods: 'Métodos', + properties: 'Propiedades', + fields: 'Campos', + constructors: 'Constructores', + namespace: 'Espacio de Nombres', + values: 'Valores', + }, + details: { + apiName: 'Nombre API', + type: 'Tipo', + signature: 'Firma', + parameters: 'Parámetros', + returnType: 'Tipo de Retorno', + throws: 'Lanza', + required: 'Requerido', + author: 'Autor', + }, + typeSuffixes: { + class: 'Clase', + interface: 'Interfaz', + enum: 'Enum', + trigger: 'Disparador', + }, + inheritance: { + inheritance: 'Herencia', + implements: 'Implementa', }, }; diff --git a/src/core/changelog/generate-change-log.ts b/src/core/changelog/generate-change-log.ts index c141a74d..a7ab528e 100644 --- a/src/core/changelog/generate-change-log.ts +++ b/src/core/changelog/generate-change-log.ts @@ -39,7 +39,7 @@ export function generateChangeLog( if (config.skipIfNoChanges && !hasChanges(changelog)) { return skip(); } - const translations = mergeTranslations(config.translations); + const translations = mergeTranslations({ changelog: config.translations }); return pipe( convertToRenderableChangelog(changelog, newManifest.types, translations), compile(translations), diff --git a/src/core/markdown/adapters/renderable-to-page-data.ts b/src/core/markdown/adapters/renderable-to-page-data.ts index 5a0cb008..ab0194cd 100644 --- a/src/core/markdown/adapters/renderable-to-page-data.ts +++ b/src/core/markdown/adapters/renderable-to-page-data.ts @@ -1,4 +1,4 @@ -import { ReferenceGuideReference, Renderable, RenderableBundle, RenderableEnum } from '../../renderables/types'; +import { ReferenceGuideReference, Renderable, RenderableBundle } from '../../renderables/types'; import { DocPageData, DocumentationBundle } from '../../shared/types'; import { pipe } from 'fp-ts/function'; import { CompilationRequest, Template } from '../../template'; diff --git a/src/core/markdown/generate-docs.ts b/src/core/markdown/generate-docs.ts index 84f436a6..908f1121 100644 --- a/src/core/markdown/generate-docs.ts +++ b/src/core/markdown/generate-docs.ts @@ -49,7 +49,7 @@ export type MarkdownGeneratorConfig = Omit< }; export function generateDocs(unparsedBundles: UnparsedSourceBundle[], config: MarkdownGeneratorConfig) { - const translations = mergeTranslations(config.translations); + const translations = mergeTranslations({ markdown: config.translations }); const convertToReferences = apply(parsedFilesToReferenceGuide, config); const convertToRenderableBundle = apply(parsedFilesToRenderableBundle, config); const convertToDocumentationBundleForTemplate = apply( diff --git a/src/core/shared/types.d.ts b/src/core/shared/types.d.ts index 63186081..05e5ae28 100644 --- a/src/core/shared/types.d.ts +++ b/src/core/shared/types.d.ts @@ -49,7 +49,7 @@ export type UserDefinedMarkdownConfig = { targetGenerator: 'markdown'; excludeTags: string[]; exclude: string[]; - translations?: UserTranslations; + translations?: UserTranslations['markdown']; } & CliConfigurableMarkdownConfig & Partial; @@ -76,7 +76,7 @@ export type UserDefinedChangelogConfig = { customObjectVisibility: string[]; exclude: string[]; skipIfNoChanges: boolean; - translations?: UserTranslations; + translations?: UserTranslations['changelog']; } & Partial; export type UserDefinedConfig = UserDefinedMarkdownConfig | UserDefinedOpenApiConfig | UserDefinedChangelogConfig; From 4723328d2cb54a55dde34fcbaf852ed66ca99261 Mon Sep 17 00:00:00 2001 From: cesarParra Date: Sun, 29 Jun 2025 09:52:45 -0400 Subject: [PATCH 5/6] Add changelog generation support with Spanish translations and example metadata --- examples/translation/README.md | 12 ++- examples/translation/apexdocs.config.ts | 10 ++- examples/translation/docs/changelog.md | 77 +++++++++++++++++++ examples/translation/package.json | 2 +- examples/translation/previous/.gitkeep | 0 .../VisibleCMT__mdt.object-meta.xml | 6 ++ .../fields/Field1__c.field-meta.xml | 11 +++ 7 files changed, 109 insertions(+), 9 deletions(-) create mode 100644 examples/translation/docs/changelog.md create mode 100644 examples/translation/previous/.gitkeep create mode 100644 examples/translation/previous/force-app/main/default/objects/VisibleCMT__mdt/VisibleCMT__mdt.object-meta.xml create mode 100644 examples/translation/previous/force-app/main/default/objects/VisibleCMT__mdt/fields/Field1__c.field-meta.xml diff --git a/examples/translation/README.md b/examples/translation/README.md index 4e5539ed..090a0d56 100644 --- a/examples/translation/README.md +++ b/examples/translation/README.md @@ -23,12 +23,10 @@ export default defineMarkdownConfig({ scope: ['public', 'global'], translations: { // Your custom translations here - markdown: { - sections: { - methods: 'Métodos', - properties: 'Propiedades', - fields: 'Campos', - }, + sections: { + methods: 'Métodos', + properties: 'Propiedades', + fields: 'Campos', }, }, }); @@ -54,7 +52,7 @@ export default defineMarkdownConfig({ sourceDir: 'src', targetDir: 'docs', scope: ['public', 'global'], - translations, + translations: translations.markdown, }); ``` diff --git a/examples/translation/apexdocs.config.ts b/examples/translation/apexdocs.config.ts index bdb4bcab..d40ab39f 100644 --- a/examples/translation/apexdocs.config.ts +++ b/examples/translation/apexdocs.config.ts @@ -1,4 +1,4 @@ -import { defineMarkdownConfig, UserTranslations } from '../../src'; +import { defineChangelogConfig, defineMarkdownConfig, UserTranslations } from '../../src'; // Spanish translations const spanishTranslations: UserTranslations['markdown'] = { @@ -38,4 +38,12 @@ export default { scope: ['global', 'public'], translations: spanishTranslations, }), + changelog: defineChangelogConfig({ + previousVersionDir: 'previous', + currentVersionDir: 'force-app', + scope: ['global', 'public'], + translations: { + title: 'Registro de Cambios', + }, + }), }; diff --git a/examples/translation/docs/changelog.md b/examples/translation/docs/changelog.md new file mode 100644 index 00000000..d8d3c4a5 --- /dev/null +++ b/examples/translation/docs/changelog.md @@ -0,0 +1,77 @@ +# Registro de Cambios + +## New Classes + +These classes are new. + +### BaseClass + +### MultiInheritanceClass + +### Url + +Represents a uniform resource locator (URL) and provides access to parts of the URL. +Enables access to the base URL used to access your Salesforce org. +### SampleClass + +aliquip ex sunt officia ullamco anim deserunt magna aliquip nisi eiusmod in sit officia veniam ex +**deserunt** ea officia exercitation laboris enim in duis quis enim eiusmod eu amet cupidatat. +### SampleException + +This is a sample exception. + +## New Interfaces + +These interfaces are new. + +### ParentInterface + +### SampleInterface + +This is a sample interface + +## New Enums + +These enums are new. + +### ReferencedEnum + +### SampleEnum + +This is a sample enum. This references ReferencedEnum . + +This description has several lines + +## New Custom Objects + +These custom objects are new. + +### Account + +### Contact + +### Event__c + +Represents an event that people can register for. +### Price_Component__c + +### Product_Price_Component__c + +### Product__c + +Product that is sold or available for sale. +### Sales_Order_Line__c + +Represents a line item on a sales order. +### Sales_Order__c + +Custom object for tracking sales orders. +### Speaker__c + +Represents a speaker at an event. + +## Removed Custom Objects + +These custom objects have been removed. + +- VisibleCMT__mdt \ No newline at end of file diff --git a/examples/translation/package.json b/examples/translation/package.json index 9accabc8..453cdbd7 100644 --- a/examples/translation/package.json +++ b/examples/translation/package.json @@ -2,7 +2,7 @@ "name": "plain-markdown", "scripts": { "docs:clean": "rimraf docs", - "docs:build": "ts-node ../../src/cli/generate.ts markdown", + "docs:build": "ts-node ../../src/cli/generate.ts", "docs:help": "ts-node ../../src/cli/generate.ts markdown --help", "docs:gen": "npm run docs:clean && npm run docs:build" }, diff --git a/examples/translation/previous/.gitkeep b/examples/translation/previous/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/examples/translation/previous/force-app/main/default/objects/VisibleCMT__mdt/VisibleCMT__mdt.object-meta.xml b/examples/translation/previous/force-app/main/default/objects/VisibleCMT__mdt/VisibleCMT__mdt.object-meta.xml new file mode 100644 index 00000000..e4b702db --- /dev/null +++ b/examples/translation/previous/force-app/main/default/objects/VisibleCMT__mdt/VisibleCMT__mdt.object-meta.xml @@ -0,0 +1,6 @@ + + + + VisibleCMTs + Public + diff --git a/examples/translation/previous/force-app/main/default/objects/VisibleCMT__mdt/fields/Field1__c.field-meta.xml b/examples/translation/previous/force-app/main/default/objects/VisibleCMT__mdt/fields/Field1__c.field-meta.xml new file mode 100644 index 00000000..8363be54 --- /dev/null +++ b/examples/translation/previous/force-app/main/default/objects/VisibleCMT__mdt/fields/Field1__c.field-meta.xml @@ -0,0 +1,11 @@ + + + Field1__c + false + DeveloperControlled + + 255 + true + Text + false + From 02d49e8aae8f64018fee4fda0d91b84fd9664ba7 Mon Sep 17 00:00:00 2001 From: cesarParra Date: Sun, 29 Jun 2025 09:55:17 -0400 Subject: [PATCH 6/6] Bump version to 3.14.0 and clean up typeDocPartial template formatting --- package.json | 2 +- src/core/markdown/templates/type-doc-partial.ts | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/package.json b/package.json index 2aa5fa61..19878de4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@cparra/apexdocs", - "version": "3.13.0", + "version": "3.14.0", "description": "Library with CLI capabilities to generate documentation for Salesforce Apex classes.", "keywords": [ "apex", diff --git a/src/core/markdown/templates/type-doc-partial.ts b/src/core/markdown/templates/type-doc-partial.ts index 8bb42d0f..13d9cb7f 100644 --- a/src/core/markdown/templates/type-doc-partial.ts +++ b/src/core/markdown/templates/type-doc-partial.ts @@ -1,8 +1,6 @@ export const typeDocPartial = ` {{#> documentablePartialTemplate}} - - {{#if doc.group}} **{{@root.translations.markdown.details.group}}** {{doc.group}} {{/if}}