Skip to content

Instantly share code, notes, and snippets.

@istarkov
Created November 4, 2021 11:41
Show Gist options
  • Save istarkov/57ba5b04959541e9c538f3da90cdf669 to your computer and use it in GitHub Desktop.
Save istarkov/57ba5b04959541e9c538f3da90cdf669 to your computer and use it in GitHub Desktop.
icu.pegjs

to exec

tsm ./icu.ts --language fr --locale fr-CH --include 'blabla/**/{translations,_translations}/*.yaml'
/*Parses ICU messages format https://messageformat.github.io/messageformat/guide/
like
{from} - {to} {results, plural,
one { # result }
many { # results }
} text {vr} rmm
{s, select,
man { He is "#"#"#" }
woman { She is # }
}
*/
Expression = w: (b:(Variable / PluralBlock / SelectBlock / AnyText) e:Expression* { return [b, ...e.flat()]})+ { return w.flat()}
// TODO: extend with formatters if needed {var, formatter} like { price, currency } or { amount, integer }
Variable = '{' _ v: Var f:(_ ',' _ fmt:Formatter _ { return fmt; })? _ '}' {return {type: 'Variable', name: v, format: f } ;}
Formatter = _ w:('integer' / 'currency' / 'fixed') _ { return w }
BlockExpression = w: (b:(Variable / BlockVariable / PluralBlock / SelectBlock / BlockAnyText) e:BlockExpression* { return [b, ...e.flat()]})+ { return w.flat()}
BlockVariable = '#' {return {type: 'BlockVariable' } ;}
SelectBlock = '{' _ v:Var _ ',' _ pk:SelectKeyword _ ',' _ ps:Select _ '}' { return {type:'SelectBlock', blockVariable: v, select: ps}}
Select = w:SelectCase+ { return {type: 'Select', cases: w}}
SelectCase = _ cs:SelectCaseValue _ '{' txt: BlockExpression '}' _ { return {'type': 'Case', 'case':cs, 'expression':txt}}
SelectCaseValue = _ w:(Integer / Case) _ { return w }
SelectKeyword = _ w:('select') _ { return w }
PluralBlock = '{' _ v:Var _ ',' _ pk:PluralKeyword _ ',' _ ps:PluralSelect _ '}' { return { type:'PluralBlock', blockVariable: v, select: ps }}
PluralSelect = w:PluralCase+ { return {type: 'PluralSelect', cases: w}}
PluralCase = _ cs:PluralSelectCaseValue _ '{' txt: BlockExpression '}' _ { return {'type': 'PluralCase', 'case':cs, 'expression':txt}}
PluralSelectCaseValue = _ w:('zero' / 'one' / 'two' / 'few' / 'many' / 'other') _ { return w } / _ '=' _ w:(Integer) _ { return w }
PluralKeyword = _ w:('plural' / 'selectordinal') _ { return w }
BlockText = ([^"{}#]+ / '"') { return text() }
BlockCommentedSymbols = (CommentedSymbols / '"#"') { return `${text().substr(1,1)}` }
BlockAnyText = a:(w: BlockCommentedSymbols+ { return w.join('') } / w:BlockText c:BlockCommentedSymbols* { return w + c.join('') })+ { return {type: 'Text', value: a.join('')} }
AnyText = a:(w: CommentedSymbols+ { return w.join('') } / w:Text c:CommentedSymbols* { return w + c.join('') })+ { return {type: 'Text', value: a.join('')} }
CommentedSymbols = ('"{"' / '"}"') { return `${text().substr(1,1)}` }
Text "text" = ([^"{}]+ / '"') { return text() }
Var "var" = [a-z]+[a-zA-Z0-9_]* { return text(); }
Case "case" = [a-zA-Z0-9_\-,]+ { return text(); }
Integer "integer"
= [0-9]+ { return Number.parseInt(text()); }
_ "whitespace"
= [ \t\n\r]*
// yarn --silent ts-node ./scripts/icu.ts --language fr-CH | yarn --silent prettier --stdin-filepath tmp.ts
import pegjs from 'pegjs';
import fs from 'fs';
import path from 'path';
import util from 'util';
import yargs from 'yargs';
import fg from 'fast-glob';
import yaml from 'yaml';
import prettier from 'prettier';
const prettierOptionsPath = prettier.resolveConfigFile.sync(process.cwd());
if (prettierOptionsPath == null) {
throw new Error('prettier options file is not found');
}
const prettierOptions = {
...prettier.resolveConfig.sync(prettierOptionsPath),
parser: 'typescript',
};
const argv = yargs(process.argv.slice(2))
.string('language')
.demandOption(['language'], 'language must be provided')
.string('locale')
.demandOption(['locale'], 'locale must be provided')
.string('include')
.coerce('include', (includeGlob: string) => {
return fg.sync(includeGlob);
})
.demandOption(['include'], 'include must be provided')
.example([['$0 --language fr --locale fr-CH', 'Use french']]).argv;
if (!('language' in argv)) {
throw new Error('argv is a Promise');
}
const languagePlural = new Intl.PluralRules(argv.locale, {
type: 'cardinal',
});
const { pluralCategories } = languagePlural.resolvedOptions();
const SCRIPTS_FOLDER = new URL('../scripts', import.meta.url);
// console.log(HELPERS_FOLDER);
const grammar = fs.readFileSync(
path.join(SCRIPTS_FOLDER.pathname, 'icu.pegjs'),
'utf-8',
);
const parser = pegjs.generate(grammar);
type Variable = {
type: 'Variable';
name: string;
format: null | 'integer' | 'currency' | 'fixed';
};
type Text = { type: 'Text'; value: string };
type BlockVariable = { type: 'BlockVariable' };
type BlockExpression = readonly (
| Text
| Variable
| BlockVariable
| PluralBlock
| SelectBlock
| Text
)[];
type PluralCase = {
type: 'PluralCase';
case: number | 'zero' | 'one' | 'two' | 'few' | 'many' | 'other';
expression: BlockExpression;
};
type PluralSelect = {
type: 'PluralSelect';
cases: readonly PluralCase[];
};
type PluralBlock = {
type: 'PluralBlock';
blockVariable: string;
select: PluralSelect;
};
type Case = {
type: 'Case';
case: number | string;
expression: BlockExpression;
};
type Select = {
type: 'Select';
cases: readonly Case[];
};
type SelectBlock = {
type: 'SelectBlock';
blockVariable: string;
select: Select;
};
type Expression = readonly (Variable | PluralBlock | SelectBlock | Text)[];
type Context = {
block: string;
arguments: Record<string, Set<string>>;
blockVariable: string | null;
hasHelpers: boolean;
hasFormat: boolean;
comment: string;
};
const createLocalContext = (comment: string): Context => ({
block: '',
arguments: {},
blockVariable: null,
hasHelpers: false,
hasFormat: false,
comment,
});
const expression = (ctx: Context, expr: Expression | BlockExpression) => {
const currBlock = ctx.block;
ctx.block = '';
expr.forEach(exp => {
switch (exp.type) {
case 'PluralBlock':
{
plural_block(ctx, exp);
}
break;
case 'Text':
{
text(ctx, exp);
}
break;
case 'Variable':
{
variable(ctx, exp);
}
break;
case 'SelectBlock':
{
select_block(ctx, exp);
}
break;
case 'BlockVariable':
{
block_variable(ctx, exp);
}
break;
}
});
ctx.block = currBlock + '`' + ctx.block.trim() + '`';
};
const addArgumentType = (ctx: Context, name: string, type: string) => {
const st = ctx.arguments[name] ?? new Set();
st.add(type);
ctx.arguments[name] = st;
};
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const block_variable = (ctx: Context, _: BlockVariable) => {
ctx.block += `\${${ctx.blockVariable}}`;
};
const variable = (ctx: Context, v: Variable) => {
ctx.block +=
v.format == null
? `\${${v.name}}`
: `\${format.${v.format}('${argv.locale}', ${v.name})}`;
addArgumentType(ctx, v.name, v.format == null ? 'string' : 'number');
ctx.hasFormat = ctx.hasFormat || v.format != null;
};
const text = (ctx: Context, txt: Text) => {
if (process.env.TRANSLATE_HELPER === 'kryakozyabra') {
let text = 'ÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿĀā';
while (text.length < txt.value.length) {
text = text + text;
}
let spaceIndex = txt.value.indexOf(' ');
while (spaceIndex !== -1) {
text = text.substr(0, spaceIndex) + ' ' + text.substr(spaceIndex);
spaceIndex = txt.value.indexOf(' ', spaceIndex + 1);
}
ctx.block += text.slice(0, txt.value.length);
return;
}
ctx.block += txt.value;
};
const plural_block = (ctx: Context, pb: PluralBlock) => {
addArgumentType(ctx, pb.blockVariable, 'number');
// In plural we will use plural
ctx.hasHelpers = true;
const bv = ctx.blockVariable;
ctx.blockVariable = pb.blockVariable;
ctx.block += '${';
const numericCases = pb.select.cases.filter(
cs => typeof cs.case === 'number',
);
const pluralCases = pb.select.cases.filter(cs => typeof cs.case === 'string');
ctx.block += `(() => {`;
if (numericCases.length > 0) {
ctx.block += `
switch(${pb.blockVariable}) {
`;
numericCases.forEach(cs => {
ctx.block += `case ${cs.case}: return `;
expression(ctx, cs.expression);
ctx.block += ';';
});
ctx.block += '}';
}
if (pluralCases.length > 0) {
ctx.block += `
switch(helpers.plural(${pb.blockVariable})) {
`;
pluralCases.forEach(cs => {
if (typeof cs.case !== 'number' && !pluralCategories.includes(cs.case)) {
throw new Error(
`Language ${argv.locale} don't has "${
cs.case
}" plural category, supported are [${pluralCategories.join(', ')}]`,
);
}
ctx.block += `case '${cs.case}': return `;
expression(ctx, cs.expression);
ctx.block += ';';
});
ctx.block += '}';
}
ctx.block += `
return '';
})()`;
ctx.block += '}';
ctx.blockVariable = bv;
};
const select_block = (ctx: Context, sb: SelectBlock) => {
const bv = ctx.blockVariable;
ctx.blockVariable = sb.blockVariable;
ctx.block += '${';
ctx.block += `(() => {
switch(${sb.blockVariable}) {
`;
let defaultBlockDefined = false;
let wideTypesEnabled = false;
sb.select.cases.forEach(cs => {
if (cs.case === 'is_empty') {
addArgumentType(ctx, sb.blockVariable, 'string');
wideTypesEnabled = true;
ctx.block += `case ''`;
} else if (cs.case === 'is_null') {
addArgumentType(ctx, sb.blockVariable, 'null');
ctx.block += 'case null';
} else if (cs.case === 'other') {
addArgumentType(ctx, sb.blockVariable, 'string');
addArgumentType(ctx, sb.blockVariable, 'number');
ctx.block += `default`;
wideTypesEnabled = true;
defaultBlockDefined = true;
} else {
const k = typeof cs.case === 'string' ? `'${cs.case}'` : cs.case;
addArgumentType(ctx, sb.blockVariable, `${k}`);
ctx.block += `case ${k}`;
}
ctx.block += `: return `;
expression(ctx, cs.expression);
ctx.block += `;`;
});
ctx.block += '}';
ctx.block += `
${defaultBlockDefined ? '' : wideTypesEnabled ? `return '';` : ''}
})()`;
ctx.block += '}';
ctx.blockVariable = bv;
};
const generateFunctionCode = (ctx: Context, name: string): string => {
const arg = `{${Object.keys(ctx.arguments).join(', ')}}`;
const argType = `{${Object.entries(ctx.arguments)
.map(([k, v]) => `${k}: ${[...v.values()].join('|')}`)
.join(', ')}}`;
return `
${ctx.comment}
export const ${name} = (${
Object.keys(ctx.arguments).length === 0 ? '' : `${arg}: ${argType}`
}):string => {
return ${ctx.block};
}`;
};
const generateImportsHelpersCode = (ctx: Context): string => {
let res = ``;
if (ctx.hasFormat) {
res += `
import * as format from '$lib/utils/format';
`;
}
if (ctx.hasHelpers) {
res += `
const intelPluralRules = new Intl.PluralRules('${argv.locale}', { type: 'cardinal' });
const helpers = {
plural: (val: number | string): 'zero' | 'one' | 'two' | 'few' | 'many' | 'other' => intelPluralRules.select(typeof val === 'string' ? Number.parseFloat(val) : val),
};
`;
}
return res;
};
const debug = <T>(v: T) =>
console.log(
util.inspect(v, {
showHidden: false,
depth: null,
colors: true,
compact: true,
}),
);
try {
if (argv.include.length === 0) {
throw new Error('include glob pattern havent found translations');
}
argv.include.forEach(yamlPath => {
const translations = yaml.parse(
fs.readFileSync(yamlPath, 'utf8'),
) as Record<string, unknown>;
const fctx: Context = createLocalContext(`
// ACHTUNG!!!
// THIS FILE IS GENERATED USING \`yarn dev:translate command\`
`);
Object.entries(translations).forEach(([translationKey, translationAll]) => {
if (translationAll == null || typeof translationAll !== 'object') {
throw new Error(
`Translation at key ${translationKey} must be an object`,
);
}
const translation = (translationAll as Record<string, string>)[
argv.language
];
if (typeof translation !== 'string') {
throw new Error(
`${translationKey} value at ${yamlPath}/${argv.language} is not a string`,
);
}
const res: Expression = parser.parse(translation);
const ctx: Context = createLocalContext(`
/**
${translation
.split('\n')
.map(line => `* ${line}`)
.join('\n')}
*/`);
expression(ctx, res);
const fn = generateFunctionCode(ctx, translationKey);
fctx.block += `
${fn}
`;
fctx.hasFormat = fctx.hasFormat || ctx.hasFormat;
fctx.hasHelpers = fctx.hasHelpers || ctx.hasHelpers;
});
const im = generateImportsHelpersCode(fctx);
const source = prettier.format(
`
${im}
${fctx.block}
`,
prettierOptions,
);
const yamlPathParsed = path.parse(yamlPath);
const tsPath = path.format({
dir: yamlPathParsed.dir,
name: yamlPathParsed.name,
ext: `.${argv.locale}.ts`,
});
fs.writeFileSync(tsPath, source, 'utf-8');
console.info(`${tsPath} saved`);
});
} catch (e) {
debug(e);
}
// const txt = ({from, to}: {from: string, to: string}) => `${from}`
grossRentM2yearly:
de: |
{price, currency} / m² / Jahr
en: |
{price, currency} / m² / year
es: |
{price, currency} / m² / año
fr: |
{price, currency} / m² / année
it: |
{price, currency} / m² / anno
priceOnRequest:
de: Auf Anfrage
en: On request
es: Bajo pedido
fr: Sur demande
it: Su richiesta
shortNumberOfRooms:
fr: |
{number_of_rooms, plural,
=0 { }
one { # pièce }
other { # pièces }
}
en: |
{number_of_rooms, plural,
=0 { }
one { # room }
other { # rooms }
}
es: |
{number_of_rooms, plural,
=0 { }
one { # habitación }
other { # habitaciones }
}
de: |
{number_of_rooms, plural,
=0 { }
one { # Zimmer }
other { # Zimmer }
}
it: |
{number_of_rooms, plural,
=0 { }
one { # camera }
other { # camere }
}
showMoreLess:
de: |
{isOpen, select,
1 { Weniger }
0 { Mehr }
}
en: |
{isOpen, select,
1 { Show less }
0 { Show more }
}
es: |
{isOpen, select,
1 { Muestra menos }
0 { Mostrar más }
}
fr: |
{isOpen, select,
1 { Voir moins }
0 { Voir plus }
}
it: |
{isOpen, select,
1 { Mostra meno }
0 { Mostra di più }
}
propertyValuationPer:
de: |
{country, select,
ch { Immobilienbewertung pro Kanton }
fr { Grundstücksbewertung pro Departement }
other { Grundstücksbewertung pro Bundesland }
}
en: |
{country, select,
ch { Property Valuation per Canton }
fr { Property Valuation per Department }
other { Property Valuation per State }
}
es: |
{country, select,
ch { Valoración de la propiedad por cantón }
fr { Valoración de la propiedad por departamento }
other { Valoración de la propiedad por estado }
}
fr: |
{country, select,
ch { Estimation immobilière par canton }
fr { Estimation immobilière par département }
other { Estimation immobilière par État }
}
it: |
{country, select,
ch { Valutazione della proprietà per cantone }
fr { Valutazione della proprietà per Dipartimento }
other { Valutazione della proprietà per Stato }
}
propertyValuationIn:
de: Immobilienbewertung im { place }
en: Property valuation in { place }
es: Valoración de la propiedad en el { place }
fr: Estimation immobilière { place }
it: Stima immobiliare nel { place }
nothingFound:
de: Nichts gefunden
en: Nothing found
es: No se ha encontrado nada
fr: Rien trouvé
it: Niente trovato
recentSaleSold:
de: Verkauft
en: Sold
es: Vendido
fr: Vendu
it: Venduto
linkTableMainTabs:
de: |
{offer_type, select,
sell { Immobilien kaufen }
rent { Immobilien mieten }
}
en: |
{offer_type, select,
sell { Real estate for sale }
rent { Real estate for rent }
}
es: |
{offer_type, select,
sell { Venta de bienes inmuebles }
rent { Inmuebles en alquiler }
}
fr: |
{offer_type, select,
sell { Biens immobiliers à vendre }
rent { Biens immobiliers à louer }
}
it: |
{offer_type, select,
sell { Immobili in vendita }
rent { Immobili in affitto }
}
linkTableTabs:
de: |
{property_type, select,
apartment { Wohnungen }
building { Gebäude }
commercial { Gewerbeimmobilien }
hospitality { Hotels und Restaurants }
house { Häuser }
parking { Parktplatz }
plot { Grundstücke }
room { Zimmer }
}
en: |
{property_type, select,
apartment { Apartments }
building { Buildings }
commercial { Commercial properties }
hospitality { Hotels & Restaurants }
house { Houses }
parking { Parking spaces }
plot { Plots }
room { Rooms }
}
es: |
{property_type, select,
apartment { Apartamentos }
building { Edificios }
commercial { Propiedades comerciales }
hospitality { Hoteles y restaurantes }
house { Casas }
parking { Plazas de aparcamiento }
plot { Parcelas }
room { Habitaciones }
}
fr: |
{property_type, select,
apartment { Appartements }
building { Immeubles }
commercial { Locaux commerciaux }
hospitality { Hotels & Restaurants }
house { Maisons }
parking { Places de parc }
plot { Terrains }
room { Pièces }
}
it: |
{property_type, select,
apartment { Appartamenti }
building { Edifici }
commercial { Proprietà commerciali }
hospitality { Hotels & Ristoranti }
house { Case }
parking { Parcheggi }
plot { Terreni }
room { Camere }
}
countryTitle:
de: |
{country, select,
ch { Switzerland }
fr { France }
es { Spain }
de { Germany }
}
en: |
{country, select,
ch { Switzerland }
fr { France }
es { Spain }
de { Germany }
}
es: |
{country, select,
ch { Switzerland }
fr { France }
es { Spain }
de { Germany }
}
fr: |
{country, select,
ch { Switzerland }
fr { France }
es { Spain }
de { Germany }
}
it: |
{country, select,
ch { Switzerland }
fr { France }
es { Spain }
de { Germany }
}
propertyTypeSelectTitle:
fr: Type de bien
en: Type
es: Type
de: Art der Immobilie
it: Genere
trustpilotReviews:
fr: avis
en: reviews
es: reseñas
de: Bewertungen
it: recensioni
trustpilotReviewsOn:
fr: avis sur
en: reviews on
es: reseñas en el
de: Bewertungen auf
it: recensioni su
trustpilotExcellent:
fr: Excellent
en: Excellent
es: Excelente
de: Hervorragend
it: Eccezionale
numberOfRooms:
fr: |
{number_of_rooms, plural,
=0 { }
one { • # pièce }
other { • # pièces }
}
en: |
{number_of_rooms, plural,
=0 { }
one { • # room }
other { • # rooms }
}
es: |
{number_of_rooms, plural,
=0 { }
one { • # habitación }
other { • # habitaciones }
}
de: |
{number_of_rooms, plural,
=0 { }
one { • # Zimmer }
other { • # Zimmer }
}
it: |
{number_of_rooms, plural,
=0 { }
one { • # camera }
other { • # camere }
}
propertyType:
fr: |
{property_type, select,
HOUSE_APPT { Maison ou Appart. }
HOUSE { Maison }
APPT { Appartement }
PROP { Terrain }
BUILDING { Immeuble }
COMMERCIAL { Commercial }
GASTRO { Hotellerie }
ROOM { Chambre }
PARK { Place de parking }
OTHER { }
}
en: |
{property_type, select,
HOUSE_APPT { House & Apartment }
HOUSE { House }
APPT { Apartment }
PROP { Plot }
BUILDING { Building }
COMMERCIAL { Commercial }
GASTRO { Hospitality }
ROOM { Room }
PARK { Parking }
OTHER { }
}
es: |
{property_type, select,
HOUSE_APPT { Maison ou Appart. }
HOUSE { Maison }
APPT { Appartement }
PROP { Terrain }
BUILDING { Immeuble }
COMMERCIAL { Commercial }
GASTRO { Hotellerie }
ROOM { Chambre }
PARK { Place de parking }
OTHER { }
}
de: |
{property_type, select,
HOUSE_APPT { Haus oder Wohnung }
HOUSE { Haus }
APPT { Wohnung }
PROP { Grundstück }
BUILDING { Gebäude }
COMMERCIAL { Büro & Gewerbe }
GASTRO { Hotel & Restaurant }
ROOM { Zimmer }
PARK { Parkplatz }
OTHER { }
}
it: |
{property_type, select,
HOUSE_APPT { Case & Appartamenti }
HOUSE { Casa }
APPT { Appartamento }
PROP { Terreno }
BUILDING { Palazzo }
COMMERCIAL { Commerciale }
GASTRO { Hotels & Ospitalità }
ROOM { Camera }
PARK { Parcheggio }
OTHER { }
}
tmp_fmt:
fr: |
{from, integer} {total, plural,
one { # résultat }
other { {total, select, 0 { } 1 { } 2 { } other { {total, integer} }} résultats }
}
en: |
{from, integer} {total, plural,
one { # résultat }
other { {total, select, 0 { } 1 { } 2 { } other { {total, integer} }} résultats }
}
es: |
{from, integer} {total, plural,
one { # résultat }
other { {total, select, 0 { } 1 { } 2 { } other { {total, integer} }} résultats }
}
de: |
{from, integer} {total, plural,
one { # résultat }
other { {total, select, 0 { } 1 { } 2 { } other { {total, integer} }} résultats }
}
it: |
{from, integer} {total, plural,
one { # résultat }
other { {total, select, 0 { } 1 { } 2 { } other { {total, integer} }} résultats }
}
@istarkov
Copy link
Author

istarkov commented Nov 4, 2021

Output example

import * as format from '$lib/utils/format';

const intelPluralRules = new Intl.PluralRules('de-CH', { type: 'cardinal' });

const helpers = {
  plural: (
    val: number | string,
  ): 'zero' | 'one' | 'two' | 'few' | 'many' | 'other' =>
    intelPluralRules.select(
      typeof val === 'string' ? Number.parseFloat(val) : val,
    ),
};

/**
 * {price, currency} / m² / Jahr
 *
 */
export const grossRentM2yearly = ({ price }: { price: number }): string => {
  return `${format.currency('de-CH', price)} / m² / Jahr`;
};

/**
 * Auf Anfrage
 */
export const priceOnRequest = (): string => {
  return `Auf Anfrage`;
};

/**
 * {number_of_rooms, plural,
 *   =0 { }
 *   one { # Zimmer }
 *   other { # Zimmer }
 * }
 *
 */
export const shortNumberOfRooms = ({
  number_of_rooms,
}: {
  number_of_rooms: number;
}): string => {
  return `${(() => {
    switch (number_of_rooms) {
      case 0:
        return ``;
    }
    switch (helpers.plural(number_of_rooms)) {
      case 'one':
        return `${number_of_rooms} Zimmer`;
      case 'other':
        return `${number_of_rooms} Zimmer`;
    }
    return '';
  })()}`;
};

/**
 * {isOpen, select,
 *   1 { Weniger }
 *   0 { Mehr }
 * }
 *
 */
export const showMoreLess = ({ isOpen }: { isOpen: 1 | 0 }): string => {
  return `${(() => {
    switch (isOpen) {
      case 1:
        return `Weniger`;
      case 0:
        return `Mehr`;
    }
  })()}`;
};

/**
 * {country, select,
 *   ch { Immobilienbewertung pro Kanton }
 *   fr { Grundstücksbewertung pro Departement }
 *   other { Grundstücksbewertung pro Bundesland }
 * }
 *
 */
export const propertyValuationPer = ({
  country,
}: {
  country: 'ch' | 'fr' | string | number;
}): string => {
  return `${(() => {
    switch (country) {
      case 'ch':
        return `Immobilienbewertung pro Kanton`;
      case 'fr':
        return `Grundstücksbewertung pro Departement`;
      default:
        return `Grundstücksbewertung pro Bundesland`;
    }
  })()}`;
};

/**
 * Immobilienbewertung im { place }
 */
export const propertyValuationIn = ({ place }: { place: string }): string => {
  return `Immobilienbewertung im ${place}`;
};

/**
 * Nichts gefunden
 */
export const nothingFound = (): string => {
  return `Nichts gefunden`;
};

/**
 * Verkauft
 */
export const recentSaleSold = (): string => {
  return `Verkauft`;
};

/**
 * {offer_type, select,
 *   sell { Immobilien kaufen }
 *   rent { Immobilien mieten }
 * }
 *
 */
export const linkTableMainTabs = ({
  offer_type,
}: {
  offer_type: 'sell' | 'rent';
}): string => {
  return `${(() => {
    switch (offer_type) {
      case 'sell':
        return `Immobilien kaufen`;
      case 'rent':
        return `Immobilien mieten`;
    }
  })()}`;
};

/**
 * {property_type, select,
 *   apartment { Wohnungen }
 *   building { Gebäude }
 *   commercial { Gewerbeimmobilien }
 *   hospitality { Hotels und Restaurants }
 *   house { Häuser }
 *   parking { Parktplatz }
 *   plot { Grundstücke }
 *   room { Zimmer }
 * }
 *
 */
export const linkTableTabs = ({
  property_type,
}: {
  property_type:
    | 'apartment'
    | 'building'
    | 'commercial'
    | 'hospitality'
    | 'house'
    | 'parking'
    | 'plot'
    | 'room';
}): string => {
  return `${(() => {
    switch (property_type) {
      case 'apartment':
        return `Wohnungen`;
      case 'building':
        return `Gebäude`;
      case 'commercial':
        return `Gewerbeimmobilien`;
      case 'hospitality':
        return `Hotels und Restaurants`;
      case 'house':
        return `Häuser`;
      case 'parking':
        return `Parktplatz`;
      case 'plot':
        return `Grundstücke`;
      case 'room':
        return `Zimmer`;
    }
  })()}`;
};

/**
 * {country, select,
 *   ch { Switzerland }
 *   fr { France }
 *   es { Spain }
 *   de { Germany }
 * }
 *
 */
export const countryTitle = ({
  country,
}: {
  country: 'ch' | 'fr' | 'es' | 'de';
}): string => {
  return `${(() => {
    switch (country) {
      case 'ch':
        return `Switzerland`;
      case 'fr':
        return `France`;
      case 'es':
        return `Spain`;
      case 'de':
        return `Germany`;
    }
  })()}`;
};

/**
 * Art der Immobilie
 */
export const propertyTypeSelectTitle = (): string => {
  return `Art der Immobilie`;
};

/**
 * Bewertungen
 */
export const trustpilotReviews = (): string => {
  return `Bewertungen`;
};

/**
 * Bewertungen auf
 */
export const trustpilotReviewsOn = (): string => {
  return `Bewertungen auf`;
};

/**
 * Hervorragend
 */
export const trustpilotExcellent = (): string => {
  return `Hervorragend`;
};

/**
 * {number_of_rooms, plural,
 *   =0 { }
 *   one { • # Zimmer }
 *   other { • # Zimmer }
 * }
 *
 */
export const numberOfRooms = ({
  number_of_rooms,
}: {
  number_of_rooms: number;
}): string => {
  return `${(() => {
    switch (number_of_rooms) {
      case 0:
        return ``;
    }
    switch (helpers.plural(number_of_rooms)) {
      case 'one':
        return `• ${number_of_rooms} Zimmer`;
      case 'other':
        return `• ${number_of_rooms} Zimmer`;
    }
    return '';
  })()}`;
};

/**
 * {property_type, select,
 *   HOUSE_APPT { Haus oder Wohnung }
 *   HOUSE { Haus }
 *   APPT { Wohnung }
 *   PROP { Grundstück }
 *   BUILDING { Gebäude }
 *   COMMERCIAL { Büro & Gewerbe }
 *   GASTRO { Hotel & Restaurant }
 *   ROOM { Zimmer }
 *   PARK { Parkplatz }
 *   OTHER { }
 * }
 *
 */
export const propertyType = ({
  property_type,
}: {
  property_type:
    | 'HOUSE_APPT'
    | 'HOUSE'
    | 'APPT'
    | 'PROP'
    | 'BUILDING'
    | 'COMMERCIAL'
    | 'GASTRO'
    | 'ROOM'
    | 'PARK'
    | 'OTHER';
}): string => {
  return `${(() => {
    switch (property_type) {
      case 'HOUSE_APPT':
        return `Haus oder Wohnung`;
      case 'HOUSE':
        return `Haus`;
      case 'APPT':
        return `Wohnung`;
      case 'PROP':
        return `Grundstück`;
      case 'BUILDING':
        return `Gebäude`;
      case 'COMMERCIAL':
        return `Büro & Gewerbe`;
      case 'GASTRO':
        return `Hotel & Restaurant`;
      case 'ROOM':
        return `Zimmer`;
      case 'PARK':
        return `Parkplatz`;
      case 'OTHER':
        return ``;
    }
  })()}`;
};

/**
 * {from, integer} {total, plural,
 *   one { # résultat }
 *   other { {total, select, 0 { } 1 { } 2 { } other { {total, integer} }} résultats }
 * }
 *
 */
export const tmp_fmt = ({
  from,
  total,
}: {
  from: number;
  total: number | 0 | 1 | 2 | string;
}): string => {
  return `${format.integer('de-CH', from)} ${(() => {
    switch (helpers.plural(total)) {
      case 'one':
        return `${total} résultat`;
      case 'other':
        return `${(() => {
          switch (total) {
            case 0:
              return ``;
            case 1:
              return ``;
            case 2:
              return ``;
            default:
              return `${format.integer('de-CH', total)}`;
          }
        })()} résultats`;
    }
    return '';
  })()}`;
};

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment