Skip to content

[No QA] Add test for matching Translations keys #4090

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Jul 29, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 88 additions & 37 deletions src/languages/es.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ export default {
cancel: 'Cancelar',
yes: 'Si',
no: 'No',
ok: 'OK',
attachment: 'Archivo Adjunto',
to: 'A',
optional: 'Opcional',
Expand All @@ -21,10 +22,14 @@ export default {
not: 'No',
signIn: 'Conectarse',
continue: 'Continuar',
firstName: 'Primer nombre',
lastName: 'Apellido',
phoneNumber: 'Número de teléfono',
email: 'Email',
and: 'y',
details: 'Detalles',
privacy: 'Intimidad',
privacyPolicy: 'Política de privacidad',
delete: 'Eliminar',
deleted: 'eliminado',
contacts: 'Contactos',
Expand Down Expand Up @@ -105,11 +110,14 @@ export default {
writeSomething: 'Escribe algo...',
blockedFromConcierge: 'Comunicación no permitida',
youAppearToBeOffline: 'Parece que estás desconectado.',
fileUploadFailed: 'Subida fallida. El archivo no es compatible.',
roomIsArchived: 'Esta sala de chat ha sido eliminada',
},
reportActionContextMenu: {
contextMenuItem: {
copyToClipboard: 'Copiar al Portapapeles',
copied: '¡Copiado!',
},
reportActionContextMenu: {
copyLink: 'Copiar Enlace',
markAsUnread: 'Marcar como no leído',
editComment: 'Editar Commentario',
Expand Down Expand Up @@ -138,6 +146,7 @@ export default {
confirm: 'Confirmar',
splitBill: 'Dividir Factura',
requestMoney: 'Pedir Dinero',
sendMoney: 'Enviar Dinero',
pay: 'Pagar',
viewDetails: 'Ver detalles',
settleExpensify: 'Pagar con Expensify',
Expand All @@ -149,6 +158,7 @@ export default {
owes: ({manager, owner}) => `${manager} debe a ${owner}`,
paid: ({owner, manager}) => `${manager} pagó a ${owner}`,
split: ({amount}) => `Dividir ${amount}`,
send: ({amount}) => `Enviar ${amount}`,
choosePaymentMethod: 'Elige el método de pago:',
noReimbursableExpenses: 'El monto de este informe es inválido',
},
Expand All @@ -172,9 +182,7 @@ export default {
profilePage: {
profile: 'Perfil',
tellUsAboutYourself: '¡Cuéntanos algo sobre tí, nos encantaría conocerte!',
firstName: 'Nombre',
john: 'Juan',
lastName: 'Apellidos',
doe: 'Nadie',
preferredPronouns: 'Pronombres preferidos',
selectYourPronouns: 'Selecciona tus pronombres',
Expand Down Expand Up @@ -233,7 +241,8 @@ export default {
enterYourUsernameToGetPaidViaPayPal: 'Escribe tu nombre de usuario para que otros puedan pagarte a través de PayPal.',
payPalMe: 'PayPal.me/',
yourPayPalUsername: 'Tu usuario de PayPal',
addPayPalAccount: 'Agregar cuenta de PayPal',
addPayPalAccount: 'Agregar Cuenta de PayPal',
growlMessageOnSave: 'Su nombre de usuario de PayPal se agregó correctamente',
editPayPalAccount: 'Actualizar cuenta de PayPal',
},
paymentsPage: {
Expand Down Expand Up @@ -263,6 +272,14 @@ export default {
expensifyIsOpenSource: 'Expensify.cash es open source',
theCode: 'el código',
openJobs: 'trabajos disponibles',
heroHeading: 'Dividir cuentas\ny chatear con amigos.',
heroDescription: {
phrase1: 'El dinero habla. Y ahora que el chat y los pagos están en un solo lugar, también es fácil. Sus pagos le llegan tan rápido como puede transmitir su punto.',
phrase2: 'New Expensify es de código abierto. Vista',
phrase3: 'el código',
phrase4: 'Vista',
phrase5: 'vacantes',
},
},
termsOfUse: {
phrase1: 'Al usar Expensify.cash, estás aceptando los',
Expand All @@ -271,9 +288,11 @@ export default {
phrase4: 'política de privacidad',
phrase5: 'El envío de dinero es brindado por Expensify Payments LLC (NMLS ID:2017010) de conformidad con sus',
phrase6: 'licencias',
phrase7: 'licenses',
},
passwordForm: {
pleaseFillOutAllFields: 'Por favor completa todos los campos',
enterYourTwoFactorAuthenticationCodeToContinue: 'Ingrese su código de autenticación de dos factores para continuar',
forgot: '¿Te has olvidado?',
twoFactorCode: 'Autenticación de 2 factores',
requiredWhen2FAEnabled: 'Obligatorio cuando A2F está habilitado',
Expand Down Expand Up @@ -309,7 +328,10 @@ export default {
},
setPasswordPage: {
enterPassword: 'Escribe una contraseña',
confirmNewPassword: 'Confirma la contraseña',
setPassword: 'Configura tu Contraseña',
passwordsDontMatch: 'Las contraseñas deben coincidir',
newPasswordPrompt: 'Su contraseña debe tener al menos 8 caracteres, \n1 letra mayúscula, 1 letra minúscula, 1 número.',
},
bankAccount: {
accountNumber: 'Número de cuenta',
Expand Down Expand Up @@ -372,6 +394,68 @@ export default {
noPhoneNumber: 'Por favor escribe un número de teléfono que incluya el código de país e.g +447814266907',
maxParticipantsReached: 'Has llegado al número máximo de participantes para un grupo.',
},
onfidoStep: {
acceptTerms: 'Al continuar con la solicitud para activar su billetera Expensify, confirma que ha leído, comprende y acepta ',
facialScan: 'Política y lanzamiento de la exploración facial de Onfido',
tryAgain: 'Intentar otra vez',
verifyIdentity: 'Verificar identidad',
genericError: 'Hubo un error al procesar este paso. Inténtalo de nuevo.',
},
additionalDetailsStep: {
headerTitle: 'Detalles adicionales',
helpText: 'Necesitamos confirmar la siguiente información antes de que podamos procesar este pago.',
helpLink: 'Obtenga más información sobre por qué necesitamos esto.',
legalFirstNameLabel: 'Primer nombre legal',
legalMiddleNameLabel: 'Segundo nombre legal',
legalLastNameLabel: 'Apellido legal',
},
termsStep: {
headerTitle: 'Condiciones y tarifas',
haveReadAndAgree: 'He leído y acepto recibir ',
electronicDisclosures: 'divulgaciones electrónicas',
agreeToThe: 'Estoy de acuerdo con la ',
walletAgreement: 'Acuerdo de billetera',
enablePayments: 'Habilitar pagos',
termsMustBeAccepted: 'Se deben aceptar los términos',
},
activateStep: {
headerTitle: 'Habilitar pagos',
activated: 'Su billetera Expensify está lista para usar.',
checkBackLater: 'Todavía estamos revisando tu información. Por favor, vuelva más tarde.',
},
companyStep: {
headerTitle: 'Información de la Empresa',
subtitle: 'Dé más información sobre su empresa.',
legalBusinessName: 'Nombre Comercial Legal',
companyWebsite: 'Company Website',
taxIDNumber: 'Tax ID Number',
companyType: 'Página Web de la Empresa',
incorporationDate: 'Fecha de Incorporación',
industryClassificationCode: 'Código de Clasificación Industrial',
confirmCompanyIsNot: 'Confirmo que esta empresa no está en el',
listOfRestrictedBusinesses: 'lista de negocios restringidos',
incorporationDatePlaceholder: 'Fecha de inicio (aaaa-mm-dd)',
companyPhonePlaceholder: '10 dígitos, sin guiones',
},
requestorStep: {
headerTitle: 'Información del solicitante',
financialRegulations: 'Las leyes fiscales y el reglamento bancario nos obliga a verificar la identidad de todo individuo que desee añadir una cuenta bancaria representando a una compañía. ',
learnMore: 'Más información',
isMyDataSafe: '¿Están seguros mis datos?',
onFidoConditions: 'Al continuar con la solicitud de añadir esta cuenta bancaria, confirma que ha leído, entiende y acepta ',
onFidoFacialScan: 'Onfido’s Facial Scan Policy and Release',
isControllingOfficer: 'Estoy autorizado a utilizar la cuenta bancaria de mi compañía para gastos de empresa',
isControllingOfficerError: 'Debe ser un oficial controlador con autorización para operar la cuenta bancaria de la compañía',
},
validationStep: {
headerTitle: 'Validar',
buttonText: 'Finalizar Configuración',
maxAttemptError: 'Se ha inhabilitado la validación de esta cuenta bancaria, debido a demasiados intentos incorrectos. Por favor contáctenos.',
description: 'Uno o dos días después de agregar su cuenta a Expensify, enviamos tres (3) transacciones a su cuenta. Tienen una línea comercial como "Expensify, Inc. Validation"',
descriptionCTA: 'Ingrese el monto de cada transacción en los campos a continuación. Ejemplo: 1.51',
reviewingInfo: '¡Gracias! Estamos revisando tu información y nos comunicaremos contigo en breve. Consulte su chat con Concierge ',
forNextSteps: ' para conocer los próximos pasos para terminar de configurar su cuenta bancaria.',
},
beneficialOwnersStep: {
beneficialOwners: 'Beneficial Owners',
additionalInformation: 'Additional Information',
Expand Down Expand Up @@ -433,39 +517,6 @@ export default {
welcomeNote: ({workspaceName}) => `¡Has sido invitado a la ${workspaceName} Espacio de trabajo! Descargue la aplicación móvil Expensify para comenzar a rastrear sus gastos.`,
},
},
companyStep: {
headerTitle: 'Información de la Empresa',
subtitle: 'Dé más información sobre su empresa.',
legalBusinessName: 'Nombre Comercial Legal',
companyWebsite: 'Company Website',
taxIDNumber: 'Tax ID Number',
companyType: 'Página Web de la Empresa',
incorporationDate: 'Fecha de Incorporación',
industryClassificationCode: 'Código de Clasificación Industrial',
confirmCompanyIsNot: 'Confirmo que esta empresa no está en el',
listOfRestrictedBusinesses: 'lista de negocios restringidos',
incorporationDatePlaceholder: 'Fecha de inicio (aaaa-mm-dd)',
companyPhonePlaceholder: '10 dígitos, sin guiones',
},
validationStep: {
headerTitle: 'Validar',
buttonText: 'Finalizar Configuración',
maxAttemptError: 'Se ha inhabilitado la validación de esta cuenta bancaria, debido a demasiados intentos incorrectos. Por favor contáctenos.',
description: 'Uno o dos días después de agregar su cuenta a Expensify, enviamos tres (3) transacciones a su cuenta. Tienen una línea comercial como "Expensify, Inc. Validation"',
descriptionCTA: 'Ingrese el monto de cada transacción en los campos a continuación. Ejemplo: 1.51',
reviewingInfo: '¡Gracias! Estamos revisando tu información y nos comunicaremos contigo en breve. Consulte su chat con Concierge ',
forNextSteps: ' para conocer los próximos pasos para terminar de configurar su cuenta bancaria.',
},
requestorStep: {
headerTitle: 'Información del solicitante',
financialRegulations: 'Las leyes fiscales y el reglamento bancario nos obliga a verificar la identidad de todo individuo que desee añadir una cuenta bancaria representando a una compañía. ',
learnMore: 'Más información',
isMyDataSafe: '¿Están seguros mis datos?',
onFidoConditions: 'Al continuar con la solicitud de añadir esta cuenta bancaria, confirma que ha leído, entiende y acepta ',
facialScan: 'la política de reconocimiento facial y la exención de Onfido',
isControllingOfficer: 'Estoy autorizado a utilizar la cuenta bancaria de mi compañía para gastos de empresa',
isControllingOfficerError: 'Debe ser un oficial controlador con autorización para operar la cuenta bancaria de la compañía',
},
requestCallPage: {
requestACall: 'Llámame por teléfono',
description: '¿Necesitas ayuda configurando tu cuenta? Nuestro equipo de guías puede ayudarte.',
Expand Down
46 changes: 45 additions & 1 deletion tests/unit/TranslateTest.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
const _ = require('underscore');
const {error: AnnotationError} = require('@actions/core');
const translate = require('../../src/libs/translate');
const translations = require('../../src/languages/translations');
const CONFIG = require('../../src/CONFIG');
const translations = require('../../src/languages/translations');

const originalTranslations = _.clone(translations);
translations.default = {
en: {
testKey1: 'English',
Expand Down Expand Up @@ -52,3 +55,44 @@ describe('translate', () => {
expect(translate.translate('en', ['testKeyGroup', 'testFunction'], {testVariable})).toBe(expectedValue);
});
});

describe('Translation Keys', () => {
function traverseKeyPath(source, path, keyPaths) {
const pathArray = keyPaths || [];
const keyPath = path ? `${path}.` : '';
_.each(_.keys(source), (key) => {
if (_.isObject(source[key]) && !_.isFunction(source[key])) {
traverseKeyPath(source[key], keyPath + key, pathArray);
} else {
pathArray.push(keyPath + key);
}
});
return pathArray;
}
const excludeLanguages = ['en', 'es-ES'];
const languages = _.without(_.keys(originalTranslations.default), ...excludeLanguages);
const mainLanguage = originalTranslations.default.en;
const mainLanguageKeys = traverseKeyPath(mainLanguage);

_.each(languages, (ln) => {
const languageKeys = traverseKeyPath(originalTranslations.default[ln]);

it(`Does ${ln} locale has all the keys`, () => {
const hasAllKeys = _.difference(mainLanguageKeys, languageKeys);
if (hasAllKeys.length) {
console.debug(`🏹 [ ${hasAllKeys.join(', ')} ] are missing from ${ln}.js`);
AnnotationError(`🏹 [ ${hasAllKeys.join(', ')} ] are missing from ${ln}.js`);
}
expect(hasAllKeys).toEqual([]);
});

it(`Does ${ln} locale has unused keys`, () => {
const hasAllKeys = _.difference(languageKeys, mainLanguageKeys);
if (hasAllKeys.length) {
console.debug(`🏹 [ ${hasAllKeys.join(', ')} ] are unused keys in ${ln}.js`);
AnnotationError(`🏹 [ ${hasAllKeys.join(', ')} ] are unused keys in ${ln}.js`);
}
expect(hasAllKeys).toEqual([]);
});
});
});