1
1
import i18next from "i18next"
2
2
import Backend from "i18next-fs-backend"
3
- import path from "path" ;
3
+ import path from "path" ;
4
4
import fs , { readdirSync , lstatSync } from "fs"
5
5
import log from "./log" ;
6
6
import { NODE_MODULES_LOCALES_PATH } from "../constants/constants" ;
7
7
8
8
export default class i18nCh {
9
-
10
9
private static instance : i18nCh
11
10
private i18nInst
12
11
private localesFolder
12
+ private nodeModulesFolder
13
13
private nameSpaces : string [ ] = [ ] ;
14
14
15
- //_______________________________________________________________________________________________
16
15
private constructor ( localesFolder = "" , nameSpaces : string [ ] = [ ] , lang = "en" ) {
17
16
try {
18
17
if ( ! localesFolder ) {
19
18
// no point to translate these errors as if they should ever happen they are input for devs, not customers
20
19
throw new Error ( "i18nCh initialization error: path to locales must be provided" )
21
20
}
22
21
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 ( ) ;
25
26
}
26
27
this . nameSpaces = nameSpaces
27
28
28
29
this . i18nInst = i18next
29
30
this . i18nInst
30
- . use ( Backend )
31
- . init ( {
31
+ . use ( Backend )
32
+ . init ( {
32
33
initImmediate : false , // false = will load the resources synchronously
33
34
ns : nameSpaces ,
34
35
partialBundledLanguages : true ,
35
36
lng : lang ,
36
37
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 ( ) ,
41
39
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
+ }
43
45
}
44
- } )
46
+ } )
45
47
}
46
48
catch ( err ) {
47
49
throw err ; // propagate
@@ -59,17 +61,16 @@ export default class i18nCh {
59
61
//_______________________________________________________________________________________________
60
62
// load all the file names (without extension: ".json") present in 'localesFolder'
61
63
private loadAllNamespaces ( ) : string [ ] {
62
- if ( ! this . localesFolder ) {
63
- return [ ] ;
64
- }
64
+ const allNamespaces = [
65
+ this . loadNamespacesFromFolder ( this . localesFolder ) ,
66
+ this . loadNamespacesFromFolder ( this . nodeModulesFolder )
67
+ ] ;
65
68
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 ( ) ) ] ;
70
70
}
71
71
72
- private loadNamespacesFromPath ( folderPath : string ) : string [ ] {
72
+ private loadNamespacesFromFolder ( baseFolder : string ) : string [ ] {
73
+ const folderPath = path . join ( baseFolder , "en" ) ;
73
74
try {
74
75
return fs . readdirSync ( folderPath )
75
76
. filter ( file => path . extname ( file ) === ".json" )
@@ -80,6 +81,26 @@ export default class i18nCh {
80
81
}
81
82
}
82
83
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
+
83
104
//_______________________________________________________________________________________________
84
105
// change to another lang
85
106
private changeLanguage ( lang : string ) {
0 commit comments