11import i18next from "i18next"
22import Backend from "i18next-fs-backend"
3- import path from "path" ;
3+ import path from "path" ;
44import fs , { readdirSync , lstatSync } from "fs"
55import log from "./log" ;
66import { NODE_MODULES_LOCALES_PATH } from "../constants/constants" ;
77
88export default class i18nCh {
9-
109 private static instance : i18nCh
1110 private i18nInst
1211 private localesFolder
12+ private nodeModulesFolder
1313 private nameSpaces : string [ ] = [ ] ;
1414
15- //_______________________________________________________________________________________________
1615 private constructor ( localesFolder = "" , nameSpaces : string [ ] = [ ] , lang = "en" ) {
1716 try {
1817 if ( ! localesFolder ) {
1918 // no point to translate these errors as if they should ever happen they are input for devs, not customers
2019 throw new Error ( "i18nCh initialization error: path to locales must be provided" )
2120 }
2221 this . localesFolder = localesFolder
23- if ( nameSpaces . length === 0 ) {
24- nameSpaces = this . loadAllNamespaces ( ) ;
22+ this . nodeModulesFolder = NODE_MODULES_LOCALES_PATH
23+
24+ if ( nameSpaces . length === 0 ) {
25+ nameSpaces = this . loadAllNamespaces ( ) ;
2526 }
2627 this . nameSpaces = nameSpaces
2728
2829 this . i18nInst = i18next
2930 this . i18nInst
30- . use ( Backend )
31- . init ( {
31+ . use ( Backend )
32+ . init ( {
3233 initImmediate : false , // false = will load the resources synchronously
3334 ns : nameSpaces ,
3435 partialBundledLanguages : true ,
3536 lng : lang ,
3637 fallbackLng : "en" ,
37- preload : readdirSync ( localesFolder ) . filter ( ( fileName ) => {
38- const joinedPath = path . join ( localesFolder , fileName )
39- return lstatSync ( joinedPath ) . isDirectory ( )
40- } ) ,
38+ preload : this . getLanguageFolders ( ) ,
4139 backend : {
42- loadPath : path . join ( localesFolder , `{{lng}}/{{ns}}.json` )
40+ loadPath : ( lng : string , ns : string ) => {
41+ const projectPath = path . join ( this . localesFolder , `${ lng } /${ ns } .json` ) ;
42+ const nodePath = path . join ( this . nodeModulesFolder , `${ lng } /${ ns } .json` ) ;
43+ return fs . existsSync ( projectPath ) ? projectPath : nodePath ;
44+ }
4345 }
44- } )
46+ } )
4547 }
4648 catch ( err ) {
4749 throw err ; // propagate
@@ -59,17 +61,16 @@ export default class i18nCh {
5961 //_______________________________________________________________________________________________
6062 // load all the file names (without extension: ".json") present in 'localesFolder'
6163 private loadAllNamespaces ( ) : string [ ] {
62- if ( ! this . localesFolder ) {
63- return [ ] ;
64- }
64+ const allNamespaces = [
65+ this . loadNamespacesFromFolder ( this . localesFolder ) ,
66+ this . loadNamespacesFromFolder ( this . nodeModulesFolder )
67+ ] ;
6568
66- const projectRootNamespaces = this . loadNamespacesFromPath ( path . join ( this . localesFolder , "en" ) ) ;
67- const nodeModulesNamespaces = this . loadNamespacesFromPath ( path . join ( NODE_MODULES_LOCALES_PATH , "en" ) ) ;
68-
69- return [ ...new Set ( [ ...projectRootNamespaces , ...nodeModulesNamespaces ] ) ] ;
69+ return [ ...new Set ( allNamespaces . flat ( ) ) ] ;
7070 }
7171
72- private loadNamespacesFromPath ( folderPath : string ) : string [ ] {
72+ private loadNamespacesFromFolder ( baseFolder : string ) : string [ ] {
73+ const folderPath = path . join ( baseFolder , "en" ) ;
7374 try {
7475 return fs . readdirSync ( folderPath )
7576 . filter ( file => path . extname ( file ) === ".json" )
@@ -80,6 +81,26 @@ export default class i18nCh {
8081 }
8182 }
8283
84+ private getLanguageFolders ( ) : string [ ] {
85+ const allFolders = [
86+ this . getFoldersFromPath ( this . localesFolder ) ,
87+ this . getFoldersFromPath ( this . nodeModulesFolder )
88+ ] ;
89+ return [ ...new Set ( allFolders . flat ( ) ) ] ;
90+ }
91+
92+ private getFoldersFromPath ( folderPath : string ) : string [ ] {
93+ try {
94+ return readdirSync ( folderPath ) . filter ( ( fileName ) => {
95+ const joinedPath = path . join ( folderPath , fileName )
96+ return lstatSync ( joinedPath ) . isDirectory ( )
97+ } ) ;
98+ } catch ( error ) {
99+ log ( `Error reading language folders from ${ folderPath } : ${ error } ` ) ;
100+ return [ ] ;
101+ }
102+ }
103+
83104 //_______________________________________________________________________________________________
84105 // change to another lang
85106 private changeLanguage ( lang : string ) {
0 commit comments