Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
helpers.translator.ts Maven / Gradle / Ivy
import i18next from 'i18next';
import { TRANSLATION } from './environment';
import { F } from './formatter';
interface TranslateOptions {
strict : boolean;
domain : string | undefined;
user : boolean;
fallback : string | undefined;
variables: object;
format : FormatFunction | undefined;
}
export interface PartialTranslateOptions extends Partial {}
export type TranslateKey = string[] | string | undefined
export type FormatFunction = (str: string) => string
export type TranslateFunction = (key: TranslateKey, options?: PartialTranslateOptions) => string | undefined
class Translator {
t : Function;
i18n : typeof i18next;
static appDomain : string = 'app'
static defaultDomain: string = 'default'
constructor(t: Function, i18n: typeof i18next) {
this.t = t
this.i18n = i18n
}
translate: TranslateFunction = (key: TranslateKey, options: PartialTranslateOptions = defaultOptions): string | undefined => {
return this.apply(key, {...defaultOptions, ...options})
}
// the main translation function, a.k.a. where the `magic` happens
private apply(key: TranslateKey, options: TranslateOptions): string | undefined {
// return the found key translation or use the fallback
// get the translation
const { keys, found, translation } = this.getTranslation(key, options)
// log if it is missing
if (translation == undefined && options.strict)
console.warn("No translation found for keys:\n%s", Translator.toKeys(keys).join("\n"))
// format the translation result
return Translator.formatTranslation(translation, {found, keys, options})
}
static toKeys(keys: TranslateKey): string[] {
return keys == undefined ? [] : Array.isArray(keys) ? keys : [keys]
}
static addDomain(domain: string, key: string): string {
return `${domain}:${key}`
}
private getTranslation(key: TranslateKey, options: TranslateOptions) {
const domain = options.domain || options.user && Translator.appDomain || undefined
const appKeys = domain
? Translator.toKeys(key).map(key => Translator.addDomain(domain as string, key))
: Translator.toKeys(key)
// for every key in the app domain, create a key in the default domain
const defaultKeys = TRANSLATION != "missing" && TRANSLATION != "all"
? appKeys
.filter(key => key.startsWith(Translator.appDomain))
.map(key => Translator.addDomain(Translator.defaultDomain, key.substring(Translator.appDomain.length + 1)))
: []
const keys = [...appKeys, ...defaultKeys]
const found = Translator.toKeys(keys).find(key => this.i18n.exists(key))
const translation = found && this.t(found, options.variables) || options.fallback
return { keys, found, translation }
}
// return the formatted translation, or the used key. Influenced by TRANSLATION.
private static formatTranslation(
translation: string | undefined,
{ found, keys, options } : {
found: string | undefined,
keys: string[],
options: TranslateOptions
}
) {
const getKeyString = () => {
const keyStr = keys.length > 0 ? keys[0] : "missing key"
if (TRANSLATION == 'all')
return `<<${keyStr}>>`
else if (found == undefined)
return `<<${keyStr} (missing)>>`
else
return `<<${found} (found)>>`
}
const format = () => {
if (typeof translation == 'string')
return options.format ? options.format(translation) : translation
else
return options.strict || TRANSLATION != "normal" ? getKeyString() : translation
}
switch (TRANSLATION) {
case 'missing':
if (found == undefined)
return getKeyString()
else
return format()
case 'found':
if (found != undefined)
return getKeyString()
else
return format()
case 'all':
return getKeyString()
default:
return format()
}
}
}
class GearsTranslator extends Translator {
/* key transformations */
private static asDetailLabelKey(detailKey: string, key: string): string { return `views.details.${detailKey}.labels.${key}` }
/* domain transformations */
static inAppDomain(key: string): string { return Translator.addDomain(G.appDomain, key) }
toValue = (value: any, label?: string, processKey?: string) => {
const getValue = () => {
const valueStr: string = typeof value != "string" ? JSON.stringify(value) : value
const valueKey = valueStr.toLocaleLowerCase()
return this.translate([
G.inAppDomain(`processes.${processKey}.values.${valueKey}`),
G.inAppDomain(`common.values.${valueKey}`),
`values.${valueKey}`
], { fallback: label || F.toSentenceCase(valueKey.replaceAll("_", " ")) })
}
const val = getValue()
return val && F.toBraceless(val) || val
}
/* specific translations with fallback behavior */
toMenuLabel = (menuKey: string, label?: string) => this.translate([
G.inAppDomain(`menu.${menuKey}`),
`menu.${menuKey}`
], {fallback: label, format: F.toSentenceCase})
toProjectName = (project: string) => this.translate(
`common.project_name`,
{user: true, fallback: project, format: F.toTitleCase}
)
toProcessTitle = (processKey: string, label?: string, language?: string) => this.translate(
`processes.${processKey}.title`,
{user: true, fallback: label, format: language == "nl" ? F.toSentenceCase : F.toTitleCase}
)
toProcessDescription = (processKey: string, label?: string) => this.translate(
`processes.${processKey}.description`,
{user: true, fallback: label, format: F.toMultiSentenceCase, strict: false}
)
toListTitle = (listKey: string, label?: string) => this.translate(
`views.lists.${listKey}.title`,
{user: true, fallback: label, format: F.toTitleCase}
)
toListShortTitle = (listKey: string, label?: string) => this.translate([
`views.lists.${listKey}.short_title`,
`views.lists.${listKey}.title`
],{user: true, fallback: label, format: F.toSentenceCase})
toListMenu = (listKey: string, label?: string) => this.translate([
`views.lists.${listKey}.menu`,
`views.common.menu`,
`common.menu`
], {user: true, fallback: label, format: F.toSentenceCase})
toDetailTitle = (detailKey: string, label?: string) => this.translate(
`views.details.${detailKey}.title`,
{user: true, fallback: label, format: F.toTitleCase}
)!
toDetailShortTitle = (detailKey: string, label?: string) => this.translate([
`views.details.${detailKey}.short_title`,
`views.details.${detailKey}.title`
], {user: true, fallback: label, format: F.toSentenceCase})
toDetailTableKey = (detailKey: string, keyFallback?: string) => {
const tableKeyFallback = this.t("group.table_key")
return this.translate(G.asDetailLabelKey(detailKey, 'table_key'),{fallback: keyFallback || tableKeyFallback, user: true, format: F.toSentenceCase} )
}
toDetailTableValue = (detailKey: string, valueFallback?: string) => {
const tableValueFallback = this.t("group.table_value")
return this.translate(G.asDetailLabelKey(detailKey, 'table_value'),{fallback: valueFallback || tableValueFallback, user: true, format: F.toSentenceCase} )
}
toTaskTitle = (processKey: string, formNr: number, options?: PartialTranslateOptions) => this.translate(
`processes.${processKey}.tasks.${formNr}.title`,
{...options, user: true, format: F.toSentenceCase}
)
toTaskDescription = (processKey: string, formNr: number, options?: PartialTranslateOptions) => this.translate(
`processes.${processKey}.tasks.${formNr}.description`,
{...options, user: true, format: F.toMultiSentenceCase}
)
toTaskShortTitle = (processKey: string, formNr: number, options?: PartialTranslateOptions) => this.translate(
`processes.${processKey}.tasks.${formNr}.short_title`,
{ fallback: this.t("task") + " " + formNr, ...options, user: true, format: F.toSentenceCase}
)
toCategory = (key: string) => this.translate(
`common.categories.${key}`,
{user: true, fallback: key, format: F.toSentenceCase}
)
static toErrorKeys = (processKey: string, key: string): string[] => {
const keyLabel = key.toLowerCase()
return [
`processes.${processKey}.errors.${keyLabel}`,
`common.errors.${keyLabel}`
]
}
toError = (processKey: string, key: string, fallback?: string) => this.translate(
G.toErrorKeys(processKey, key),
{user: true, fallback: fallback, strict: false, format: F.toSentenceCase}
)
static toLabelKeys = (processKey: string, key: string): string[] => {
const keyLabel = key.toLowerCase()
return [
`processes.${processKey}.labels.${keyLabel}`,
`common.labels.${keyLabel}`
]
}
toLabel = (processKey: string, key: string, label?: string) => this.translate(
G.toLabelKeys(processKey, key),
{user: true, fallback: label, strict: false, format: F.toSentenceCase}
)
toListLabel = (listKey: string, key: string, label?: string) => {
const keyLabel = key.toLowerCase()
return this.translate([
`views.lists.${listKey}.labels.${keyLabel}`,
`views.common.${listKey}.labels.${keyLabel}`,
`common.labels.${keyLabel}`,
], {user: true, fallback: label, format: F.toSentenceCase})
}
toDetailLabel = (detailKey: string, key: string, label?: string) => {
const keyLabel = key.toLowerCase()
return this.translate([
`views.details.${detailKey}.labels.${keyLabel}`,
`views.common.${detailKey}.labels.${keyLabel}`,
`common.labels.${keyLabel}`,
], {user: true, fallback: label, format: F.toSentenceCase})
}
toListLink = (listKey: string, link: string, label?: string) => this.translate([
`views.lists.${listKey}.links.${link}`,
`views.common.links.${link}`,
`common.links.${link}`,
], {user: true, fallback: label, format: F.toSentenceCase})
toDetailLink = (detailKey: string, link: string, label?: string) => this.translate([
`views.details.${detailKey}.links.${link}`,
`views.common.links.${link}`,
`common.links.${link}`,
], {user: true, fallback: label, format: F.toSentenceCase})
toActorName = (processKey: string, actor: string, label?: string) => this.translate([
`processes.${processKey}.actors.${actor}`,
`common.actors.${actor}`
], { user: true, fallback: label || actor, strict: false, format: F.toTitleCase})
}
const G: typeof GearsTranslator = GearsTranslator
const defaultOptions: TranslateOptions = {
strict : false,
domain : undefined,
user : false,
fallback : undefined,
variables: {},
format : (str: string) => str.replace(/[{}]/g, '')
}
export {GearsTranslator as default, GearsTranslator as T}