@@ -6,9 +6,9 @@ const { isIP } = require('net');
66// const formatSpecifiers = require('format-specifiers');
77const Redis = require ( '@ladjs/redis' ) ;
88const _ = require ( 'lodash' ) ;
9- const autoLinkHeadings = require ( 'remark-autolink-headings' ) ;
9+ // const autoLinkHeadings = require('remark-autolink-headings');
1010const debug = require ( 'debug' ) ( 'mandarin' ) ;
11- const emoji = require ( 'remark-emoji' ) ;
11+ // const emoji = require('remark-emoji');
1212const globby = require ( 'globby' ) ;
1313const isFQDN = require ( 'is-fqdn' ) ;
1414const isSANB = require ( 'is-string-and-not-blank' ) ;
@@ -19,9 +19,10 @@ const pMapSeries = require('p-map-series');
1919const pify = require ( 'pify' ) ;
2020const rehypeRaw = require ( 'rehype-raw' ) ;
2121const rehypeRewrite = require ( 'rehype-rewrite' ) ;
22- const rehypeStringify = require ( 'rehype-stringify' ) ;
22+ // const rehypeStringify = require('rehype-stringify');
2323const remarkParse = require ( 'remark-parse' ) ;
2424const remarkPresetGitHub = require ( 'remark-preset-github' ) ;
25+ const remarkStringify = require ( 'remark-stringify' ) ;
2526const remarkRehype = require ( 'remark-rehype' ) ;
2627const revHash = require ( 'rev-hash' ) ;
2728const sharedConfig = require ( '@ladjs/shared-config' ) ;
@@ -31,6 +32,7 @@ const universalify = require('universalify');
3132const vfile = require ( 'to-vfile' ) ;
3233const { v2 } = require ( '@google-cloud/translate' ) ;
3334const { isEmail, isURL } = require ( 'validator' ) ;
35+ const visit = require ( 'unist-util-visit' ) ;
3436
3537const isoCodes = Object . keys ( languages . getAlpha2Codes ( ) ) ;
3638const writeFile = pify ( fs . writeFile ) ;
@@ -59,6 +61,22 @@ function parsePreAndPostWhitespace(str) {
5961 return [ str . slice ( 0 , index ) , value , str . slice ( index + value . length ) ] ;
6062}
6163
64+ // Custom plugin to add the {#id} syntax to the end of the heading text.
65+ const addCustomIdToHeadingText = ( ) => ( tree ) => {
66+ visit ( tree , 'heading' , ( node ) => {
67+ // `remark-slug` has already added the ID to `node.properties.id`.
68+ const slug = node . data ?. id ; // Use optional chaining for safety.
69+
70+ if ( slug ) {
71+ // Append a new text node containing the custom ID syntax.
72+ node . children . push ( {
73+ type : 'text' ,
74+ value : ` {#${ slug } }`
75+ } ) ;
76+ }
77+ } ) ;
78+ } ;
79+
6280// GitHub alert patterns
6381const GITHUB_ALERT_PATTERNS = [
6482 { pattern : / ^ > \s * \[ ! N O T E \] .* $ / gm, type : 'NOTE' } ,
@@ -113,10 +131,6 @@ class Mandarin {
113131 }
114132 } ,
115133 //
116- // New option to enable text-based translation
117- //
118- useTextTranslation : true ,
119- //
120134 // Concurrency limit for parallel translations
121135 //
122136 concurrency : 5
@@ -167,9 +181,9 @@ class Mandarin {
167181 }
168182
169183 // Improved method for text-based markdown translation using Promise.all and p-map
170- async parseMarkdownFileText ( filePath ) {
171- debug ( 'parseMarkdownFileText' , filePath ) ;
172- const content = await readFile ( filePath , 'utf8' ) ;
184+ async parseMarkdownFileText ( content , locale ) {
185+ // debug('parseMarkdownFileText', filePath);
186+ // const content = await readFile(filePath, 'utf8');
173187
174188 // don't translate the main file.md file, only for other locales
175189 const locales = this . config . i18n . config . locales . filter (
@@ -517,17 +531,13 @@ class Mandarin {
517531 async parseMarkdownFile ( filePath ) {
518532 debug ( 'parseMarkdownFile' , filePath ) ;
519533
520- // Use text-based translation if enabled
521- if ( this . config . useTextTranslation ) {
522- return this . parseMarkdownFileText ( filePath ) ;
523- }
524-
525534 // Original HTML-based implementation
526535 const markdown = await vfile . read ( filePath ) ;
527536 // don't translate the main file.md file, only for other locales
528537 const locales = this . config . i18n . config . locales . filter (
529538 ( locale ) => locale !== this . config . i18n . config . defaultLocale
530539 ) ;
540+
531541 const files = await Promise . all (
532542 locales . map ( ( locale ) => {
533543 return new Promise ( ( resolve , reject ) => {
@@ -536,51 +546,27 @@ class Mandarin {
536546 . use ( remarkPresetGitHub )
537547 . use ( remarkParse )
538548 . use ( slug )
549+ /*
539550 .use(autoLinkHeadings, {
540- behavior : 'prepend' ,
551+ behavior: 'prepend', // Use 'prepend' or 'append', but NOT 'wrap'.
552+ // The content for the new, separate link.
541553 content: {
542- type : 'element' ,
543- tagName : 'i' ,
544- properties : {
545- className : [ 'fa' , 'fa-link' , 'mr-2' , 'text-dark' ]
546- } ,
547- children : [ ]
554+ type: 'text',
555+ value: '🔗', // Using an emoji for the link content.
556+ },
557+ // Link properties can be added if needed, e.g., for CSS classes.
558+ properties: {
559+ ariaHidden: 'true',
560+ class: 'anchor'
548561 }
549562 })
550- . use ( emoji )
551- . use ( remarkRehype , { allowDangerousHtml : true } )
552- . use ( rehypeRaw )
553- . data ( 'settings' , { fragment : true , emitParseErrors : true } )
554- . use ( rehypeRewrite , ( node , index , parent ) => {
555- if (
556- locale !== 'en' &&
557- node . type === 'text' &&
558- parent . tagName !== 'code' &&
559- isSANB ( node . value ) &&
560- node . value !== node . value . toUpperCase ( )
561- ) {
562- // if the `parent.tagName` is `code`
563- // or if the `node.value` is empty string (and not just \n either)
564- // or if the `node.value` when converted to uppercase is the same (e.g. abbreviation)
565- // then do not translate the value using i18n
566- // otherwise translate the value and set the new node value
567- //
568- // NOTE: we must strip the preceeding and succeeding whitespace and line breaks
569- // and then add them back after the string is successfully translated
570- //
571- const [ pre , phrase , post ] = parsePreAndPostWhitespace (
572- node . value
573- ) ;
574- node . value =
575- pre +
576- this . config . i18n . api . t ( {
577- phrase,
578- locale
579- } ) +
580- post ;
581- }
563+ */
564+ . use ( addCustomIdToHeadingText )
565+ . use ( remarkStringify , {
566+ // Important: This option prevents the processor from escaping the `{` and `}`
567+ // characters in our custom ID.
568+ fences : true
582569 } )
583- . use ( rehypeStringify )
584570 . process ( markdown , ( err , file ) => {
585571 if ( err ) return reject ( err ) ;
586572 resolve ( { locale, content : String ( file ) } ) ;
@@ -594,8 +580,9 @@ class Mandarin {
594580 filePath ,
595581 file . locale
596582 ) ;
583+ const translatedContent = await this . translateMarkdownContent ( file . content , file . locale ) ;
597584 debug ( 'writing file' , localizedFilePath ) ;
598- await writeFile ( localizedFilePath , file . content ) ;
585+ await writeFile ( localizedFilePath , translatedContent ) ;
599586 } )
600587 ) ;
601588 }
0 commit comments