file description import type { HibikiClient } from "./Client" ; import type { LocaleString , LocaleStrings } from "../typings/locales" ; import { logger } from "../utils/logger" ; import config from "../../config.json" ; import { readFile , readdir } from "fs" ; export class LocaleSystem { locales : Record < string , string > ; constructor ( path ) { this . locales = { } ; if ( path ) this . updateLocales ( path ) ; } updateLocales ( path ) { readdir ( path , { withFileTypes : true } , ( err , files ) => { if ( err ) throw err ; files . forEach ( ( file ) => { if ( file . isDirectory ( ) ) this . updateLocales ( `${ path }/${ file . name }` ) ; else if ( file . isFile ( ) ) { readFile ( `${ path }/${ file . name }` , { encoding : "utf8" } , ( _err , fileData ) => { if ( err ) throw err ; const localeObj = { } ; const data = JSON . parse ( fileData ) ; Object . entries ( data ) . forEach ( ( locale ) => { if ( typeof locale [ 1 ] === "object" ) { localeObj [ locale [ 0 ] ] = { } ; Object . entries ( locale [ 1 ] ) . forEach ( ( string ) => { if ( string [ 1 ] . length > 0 ) localeObj [ locale [ 0 ] ] [ string [ 0 ] ] = string [ 1 ] ; } ) ; } else { localeObj [ locale [ 0 ] ] = locale [ 1 ] ; } } ) ; this . locales [ file . name . replace ( /.json/ , "" ) ] = localeObj as string ; } ) ; } } ) ; } ) ; } getLocale ( language , fieldName , args ? ) { const category = fieldName . split ( "." ) ; let output = "" ; output = this . _findLocaleString ( language , fieldName , category ) ; if ( ! output ) { const defaultLocale = config . defaultLocale ?? "en" ; const isDefault = language === defaultLocale ; if ( language ) logger . warn ( `${ fieldName } is missing in the string table for ${ language }${ ! isDefault ? ", searching in default locale string table" : "" }` ) ; return isDefault ? ( fieldName as string ) : this . getLocale ( defaultLocale , fieldName , args ) ; } if ( args ) { Object . getOwnPropertyNames ( args ) . forEach ( ( arg ) => { const argumentRegex = new RegExp ( `{${ arg }}` ) ; const pluralRegex = new RegExp ( `{${ arg }:#([^{}]+)#!([^{}]+)!(?:\\?([^{}]+)\\?)?}` ) ; const optionalRegex = new RegExp ( `({optional:${ arg }:(.+)(?:{\\w})?})` ) ; const optional = optionalRegex . exec ( output ) ; if ( optional ) output = output . replace ( optional [ 1 ] , typeof args [ arg ] != "undefined" ? optional [ 2 ] : "" ) ; output = output . replace ( argumentRegex , args [ arg ] ) ; const plurals = pluralRegex . exec ( output ) ; if ( plurals ) { let plural = "" ; if ( args [ arg ] === 1 || ( args [ arg ] > 1 && args [ arg ] < 2 ) ) plural = plurals [ 2 ] ; else if ( plurals [ 3 ] && args [ arg ] >= 2 && args [ arg ] <= 4 ) plural = plurals [ 3 ] ; else plural = plurals [ 1 ] ; output = output . replace ( plurals [ 0 ] , plural ) ; } else if ( ! plurals ) output = output . replace ( `{${ arg }}` , args [ arg ] ) ; } ) ; } const optionalRegex = new RegExp ( `({optional:.+:(.+)})` ) ; const optional = optionalRegex . exec ( output ) ; if ( optional ) output = output . replace ( optional [ 1 ] , "" ) ; return output ; } getLocaleFunction ( language ) { return ( fieldName , args ? ) => this . getLocale ( language , fieldName , args ) ; } async getUserLocale ( user , bot , handler = false ) { let locale = "" ; const userConfig = await bot . db . getUserConfig ( user ) ; if ( userConfig ?. locale ) locale = userConfig . locale ; else if ( handler === false ) locale = config . defaultLocale ? config . defaultLocale : "en" ; return locale ; } private _findLocaleString ( language , fieldName , category ) { if ( ! this . locales ?. [ language ] ) return ; let output = "" ; if ( ! this . locales ?. [ language ] ?. [ category [ 0 ] ] && ! this . locales ?. [ fieldName ] ) { Object . getOwnPropertyNames ( this . locales [ language ] ) . forEach ( ( cat ) => { Object . getOwnPropertyNames ( this . locales [ language ] [ cat ] ) . forEach ( ( locale ) => { if ( locale === fieldName ) output = this . locales [ language ] [ cat ] [ locale ] ; } ) ; } ) ; } else if ( this . locales ?. [ language ] ?. [ category [ 0 ] ] && this . locales ?. [ language ] ?. [ category [ 0 ] ] ?. [ category [ 1 ] ] ) { output = this . locales [ language ] [ category [ 0 ] ] [ category [ 1 ] ] ; } else if ( this . locales ?. [ language ] ?. [ fieldName ] ) { output = this . locales [ language ] [ fieldName ] ; } return output ; } }