diff --git a/app/[locale]/tag-data.json b/app/[locale]/tag-data.json
index a3bf4d9..00ddff6 100644
--- a/app/[locale]/tag-data.json
+++ b/app/[locale]/tag-data.json
@@ -3,10 +3,10 @@
"frontend": 1,
"backend": 2,
"fullstack": 1,
- "javascript": 4,
- "typescript": 4,
- "testing": 2,
- "tdd": 1,
+ "javascript": 5,
+ "typescript": 5,
+ "testing": 3,
+ "tdd": 2,
"nextjs": 2,
"laravel": 3,
"php": 3,
@@ -17,10 +17,10 @@
"frontend": 1,
"backend": 2,
"fullstack": 1,
- "javascript": 4,
- "typescript": 4,
- "testing": 2,
- "tdd": 1,
+ "javascript": 5,
+ "typescript": 5,
+ "testing": 3,
+ "tdd": 2,
"nextjs": 2,
"laravel": 3,
"php": 3,
diff --git a/data/blog/en/katas-sustainable-testing-ts/kata-03-camel-case-converter.mdx b/data/blog/en/katas-sustainable-testing-ts/kata-03-camel-case-converter.mdx
new file mode 100644
index 0000000..0f2077e
--- /dev/null
+++ b/data/blog/en/katas-sustainable-testing-ts/kata-03-camel-case-converter.mdx
@@ -0,0 +1,273 @@
+---
+title: "Kata 03 with TypeScript: CamelCase Converter"
+series:
+ order: 3
+ title: "Sustainable Testing Katas in TypeScript"
+date: '2024/10/04'
+lastmod: '2024/10/04'
+language: en
+tags: ['testing', 'tdd', 'javascript', 'typescript']
+authors: ['default']
+draft: false
+featured: false
+summary: In this article of the series "Sustainable Testing Katas in TypeScript", we'll see how to implement a CamelCase converter using TDD and Jest.
+---
+
+> The katas of this series are proposed exercises in the excellent course [Testing Sostenible con TypeScript](https://academy.softwarecrafters.io/p/curso) by Miguel A. Gómez and Carlos Blé
+
+## Introduction
+
+There are two types of `CamelCase`: `UpperCamelCase` and `lowerCamelCase`. The first one is usually known as `PascalCase`, while the second one is which is associated the most with this naming convention. On this occasion, the converter in question will be for the first case. For simplicity, `CamelCase` will be used as an alias for `UpperCamelCase`.
+
+In this article, we will see how to create a function that allows to convert a string to `CamelCase` using TDD. In order to keep the article concise, the `Red-Green-Refactor` phases will be implicit. If you don't know what I'm talking about, take a look at the [previous article](https://charlie2code.com/blog/katas-sustainable-testing-ts/kata-02-fizzbuzz) of this series. There, this topic is explained step by step with the classic FizzBuzz problem.
+
+
+
+## Constraints
+
+We will assume that this conversion is from expressions that meet the following criteria:
+
+- The letters of the words can only be lowercase, or if there are any uppercase letters, these can only be at the first position of each word.
+- The separators between words can only be spaces, dashes or underscores.
+
+This means that a word like `FOo` would not be properly converted to `Foo`.
+
+There are two reasons for this:
+
+1. A converter of this type is used for expressions that already use another naming convention.
+2. No one in their right mind would use `MiXeDcAsE` (just reading it is painful, and I can't even tell you what it was like to write it).
+
+> To make this exercise, we will use a template that you can find [here](https://github.com/softwarecrafters-io/ts-eslint-prettier-jest)
+
+## Creating the converter
+
+Let's create two files: `camel-case-converter.ts` and `camel-case-converter.test.ts`. The first one will contain the `toCamelCase` function and the second one, the tests.
+
+```ts
+// src/core/camel-case-converter.ts
+export function toCamelCase(string: string) {
+ // implementation goes here
+}
+```
+
+```ts
+// src/tests/camel-case-converter.test.ts
+import {toCamelCase} from "../core/camel-case-converter";
+```
+
+To group our tests, let's define a suite that contains `CamelCaseConverter` as description.
+
+```ts
+// src/tests/camel-case-converter.test.ts
+describe("CamelCaseConverter", () => {
+ // tests go here
+});
+```
+
+We will address the following cases, in the given order:
+
+1. It should return an empty string for an empty string (or return it as it is).
+2. It should return the same word for a word with the first letter capitalized.
+3. It should return the words joined in `CamelCase` format for words separated by spaces with the first letter capitalized.
+4. It should return the words joined in `CamelCase` format for words separated by hyphens with the first letter capitalized.
+5. It should return the word with the first letter capitalized for a word with the first letter in lowercase.
+6. It should return the words joined in `CamelCase` format for lowercase words.
+
+### Case 1
+
+**1. It should return an empty string for an empty string (or return it as it is).**
+
+We create the test:
+
+```ts
+// src/tests/camel-case-converter.test.ts
+it("should return an empty string for an empty string", () => {
+ const result = toCamelCase("");
+ const expected = "";
+
+ expect(result).toBe(expected);
+});
+```
+
+The minimum implementation would be to simply return the empty string:
+
+```ts
+// src/core/camel-case-converter.ts
+export function toCamelCase(string: string) {
+ return "";
+}
+```
+
+There's nothing to be refactored.
+
+### Case 2
+
+**2. It should return the same word for a word with the first letter capitalized.**
+
+We create the test:
+
+```ts
+// src/tests/camel-case-converter.test.ts
+it("should return the same word for a word with the first letter capitalized", () => {
+ const result = toCamelCase("Foo");
+ const expected = "Foo";
+
+ expect(result).toBe(expected);
+});
+```
+
+The minimum implementation would be to return the string received by the function, and this would still work for the case 1.
+
+```ts
+// src/core/camel-case-converter.ts
+export function toCamelCase(string: string) {
+ return string;
+}
+```
+
+There's nothing to be refactored.
+
+### Case 3
+
+**3. It should return the words joined in `CamelCase` format for words separated by spaces with the first letter capitalized.**
+
+We create the test:
+
+```ts
+// src/tests/camel-case-converter.test.ts
+it("should return the words chained in CamelCase format for words separated by spaces with the first letter capitalized", () => {
+ const result = toCamelCase("Foo Bar");
+ const expected = "FooBar";
+
+ expect(result).toBe(expected);
+});
+```
+
+The minimum implementation, so as to not deal with regular expressions yet, would be to split the string using a space as separator, and then join the elements with no separator.
+
+```ts
+// src/core/camel-case-converter.ts
+export function toCamelCase(string: string) {
+ return string.split(' ').join('');
+}
+```
+
+The previous tests would still pass, of course. In those cases the result of splitting the string would be a single-element array. Again, there's nothing to be refactored.
+
+### Case 4
+
+**4. It should return the words joined in `CamelCase` format for words separated by hyphens with the first letter capitalized.**
+
+We create the test:
+
+```ts
+// src/tests/camel-case-converter.test.ts
+it("should return the words chained in CamelCase format for words separated by hyphens with the first letter capitalized", () => {
+ const result = toCamelCase("Foo_Bar-Foo");
+ const expected = "FooBarFoo";
+
+ expect(result).toBe(expected);
+});
+```
+
+The minimum implementation would be, now, would be to use a regular expression to separate the string by spaces and hyphens, whether they are dashes or underscores, and then join the elements with no separator.
+
+```ts
+// src/core/camel-case-converter.ts
+export function toCamelCase(string: string) {
+ return string.split(/[-_\s]/).join('');
+}
+```
+
+`\s` is used instead of `' '` for clarity. Again, the refactoring is like the RGB to be a good programmer, we don't need it.
+
+### Case 5
+
+**5. It should return the word with the first letter capitalized for a word with the first letter in lowercase.**
+
+We create the test:
+
+```ts
+// src/tests/camel-case-converter.test.ts
+it("should return the word with the first letter capitalized for a word with the first letter in lowercase", () => {
+ const result = toCamelCase("foo");
+ const expected = "Foo";
+
+ expect(result).toBe(expected);
+});
+```
+
+Here, the minimum implementation would be to solve this conversion problem from lowercase to uppercase for only one word.
+
+```ts
+// src/core/camel-case-converter.ts
+export function toCamelCase(string: string) {
+ const word = string.split(/[-_\s]/).join('');
+ return word.charAt(0).toUpperCase() + word.substring(1);
+}
+```
+
+We first remove the separators, join the letters back and then we convert the first letter to uppercase and join it to the rest of the string. Again, there's nothing to be refactored.
+
+### Case 6
+
+**6. It should return the words joined in `CamelCase` format for lowercase words.**
+
+We come to the last case, what do we have to do first? Create the test:
+
+```ts
+// src/tests/camel-case-converter.test.ts
+it("should return the words chained in CamelCase format for lowercase words", () => {
+ const result = toCamelCase("foo_bar foo");
+ const expected = "FooBarFoo";
+
+ expect(result).toBe(expected);
+});
+```
+
+The minimum implementation that we need starts from the previous case. We already know how to handle one word, so we just have to generalize it for any quantity. That is: separate the words using the given separators, convert the first letter of each one to uppercase and join it with the rest of the word, and finally join the results of each word.
+
+```ts
+// src/core/camel-case-converter.ts
+export function toCamelCase(string: string) {
+ const words = string.split(/[-_\s]/);
+ return words.map((word) => word.charAt(0).toUpperCase() + word.substring(1)).join('');
+}
+```
+
+Here, everything is joined until the end because it wouldn't make sense to remove the separators, join the elements and separate again. In this last case, refactoring would not be necessary either.
+
+Voila! Another function implemented using TDD. Yes, it is not called magic, although sometimes it seems that way because of how fantastic it becomes (my blog, my bad jokes).
+
+## Bonus: Other Cases
+
+If you want to extend the function so that it converts expressions containing mixed letters, it would be needed to convert all the uppercase letters, which are not the first letter of a word, to lowercase. This would be achieved, for instance, with a regular expression that uses a `negative lookbehind`. I was thinking about just give you the concept, but since we are already here, this would be the regular expression:
+
+```ts
+/(? {
+ return match.toLowerCase();
+})
+```
+
+Just keep in mind that, using the TypeScript configuration of the template, `replaceAll` is not supported because the configuration uses `ES5`. You would have to change it for something like `es2021`:
+
+```json
+// tsconfig.json
+"target": "es2021"
+```
+
+## Link to GitHub repository
+
+You can find this kata, and the rest of them, [here](https://github.com/carlos-talavera/katas-sustainable-testing-ts).
+
+## Conclusion
+
+Don't worry if this process doesn't seem so easy at first, repeat it until it is clear to you what it is to create software with testing in mind and not the software itself. Create your own functions and tests of whatever you are interested in or seems fun to you, and little by little it will make more sense. The key is to think about **_what_** has to happen, and the implementation you need will come to you naturally.
+
+I hope this other TDD example is useful to you and it helps you to have a clearer vision on how to address problems using this approach. You know the drill, if you have any question or want to share something, leave it in the comments :)
\ No newline at end of file
diff --git a/data/blog/es/katas-sustainable-testing-ts/kata-03-camel-case-converter.mdx b/data/blog/es/katas-sustainable-testing-ts/kata-03-camel-case-converter.mdx
new file mode 100644
index 0000000..4017dc5
--- /dev/null
+++ b/data/blog/es/katas-sustainable-testing-ts/kata-03-camel-case-converter.mdx
@@ -0,0 +1,273 @@
+---
+title: "Kata 03 con TypeScript: Convertidor de CamelCase"
+series:
+ order: 3
+ title: "Katas Testing Sostenible con TypeScript"
+date: '2024/10/04'
+lastmod: '2024/10/04'
+language: es
+tags: ['testing', 'tdd', 'javascript', 'typescript']
+authors: ['default']
+draft: false
+featured: false
+summary: En este artículo de la serie "Katas Testing Sostenible con TypeScript", veremos cómo implementar un convertidor de CamelCase utilizando TDD y Jest.
+---
+
+> Las katas de esta serie son ejercicios propuestos en el excelente curso [Testing Sostenible con TypeScript](https://academy.softwarecrafters.io/p/curso) de Miguel A. Gómez y Carlos Blé
+
+## Introducción
+
+Existen dos tipos de `CamelCase`: `UpperCamelCase` y `lowerCamelCase`. El primero suele ser conocido como `PascalCase`, mientras que el segundo es el que más se asocia a esta convención de nombres. En esta ocasión, el convertidor en cuestión será para el primer caso. Por simplicidad, se utilizará `CamelCase` como alias de `UpperCamelCase`.
+
+En este artículo, veremos cómo crear una función que permita convertir una cadena de texto a `CamelCase` utilizando TDD. Para mantener el artículo conciso, las fases de `Red-Green-Refactor` estarán implícitas. Si no sabes de qué hablo, checa el [artículo anterior](https://charlie2code.com/es/blog/katas-sustainable-testing-ts/kata-02-fizzbuzz) de esta serie. Ahí se explica paso a paso este tema con el clásico problema de FizzBuzz.
+
+
+
+## Restricciones
+
+Asumiremos que la conversión es a partir de expresiones que cumplan las siguientes características:
+
+- Las letras de las palabras pueden ser solo minúsculas, o si hay letras mayúsculas, estas solo pueden estar en la primera posición de cada palabra.
+- Los separadores entre palabras pueden ser solo espacios, guiones medios o bajos.
+
+Eso significa que una palabra como `FOo` no sería convertida correctamente a `Foo`.
+
+Hay dos razones para esto:
+
+1. Un convertidor de este tipo se utiliza para expresiones que ya utilizan otra convención de nombres.
+2. Nadie en su sano juicio utilizaría `MiXeDcAsE` (solo leerlo es doloroso, y ni te cuento cómo fue escribirlo).
+
+> Para realizar este ejercicio, utilizaremos una plantilla que puedes encontrar [aquí](https://github.com/softwarecrafters-io/ts-eslint-prettier-jest)
+
+## Creación del convertidor
+
+Vamos a crear dos archivos: `camel-case-converter.ts` y `camel-case-converter.test.ts`. El primero contendrá la función `toCamelCase` y el segundo, las pruebas.
+
+```ts
+// src/core/camel-case-converter.ts
+export function toCamelCase(string: string) {
+ // implementación aquí
+}
+```
+
+```ts
+// src/tests/camel-case-converter.test.ts
+import {toCamelCase} from "../core/camel-case-converter";
+```
+
+Para agrupar nuestras pruebas, vamos a definir una suite que contenga `CamelCaseConverter` como descripción.
+
+```ts
+// src/tests/camel-case-converter.test.ts
+describe("CamelCaseConverter", () => {
+ // pruebas aquí
+});
+```
+
+Abordaremos los siguientes casos, en el orden dado:
+
+1. Debe regresar una cadena vacía para una cadena vacía (o bien, regresarla tal cual).
+2. Debe regresar la misma palabra para una palabra con la primera letra en mayúsculas.
+3. Debe regresar las palabras unidas en formato `CamelCase` para palabras separadas por espacios con la primera letra en mayúsculas.
+4. Debe regresar las palabras unidas en formato `CamelCase` para palabras separadas por guiones con la primera letra en mayúsculas.
+5. Debe regresar la palabra con la primera letra en mayúsculas para una palabra con la primera letra en minúsculas.
+6. Debe regresar las palabras unidas en formato `CamelCase` para palabras en minúsculas.
+
+### Caso 1
+
+**1. Debe regresar una cadena vacía para una cadena vacía (o bien, regresarla tal cual).**
+
+Creamos la prueba:
+
+```ts
+// src/tests/camel-case-converter.test.ts
+it("should return an empty string for an empty string", () => {
+ const result = toCamelCase("");
+ const expected = "";
+
+ expect(result).toBe(expected);
+});
+```
+
+La implementación mínima sería simplemente regresar la cadena vacía:
+
+```ts
+// src/core/camel-case-converter.ts
+export function toCamelCase(string: string) {
+ return "";
+}
+```
+
+No hay nada por refactorizar.
+
+### Caso 2
+
+**2. Debe regresar la misma palabra para una palabra con la primera letra en mayúsculas.**
+
+Creamos la prueba:
+
+```ts
+// src/tests/camel-case-converter.test.ts
+it("should return the same word for a word with the first letter capitalized", () => {
+ const result = toCamelCase("Foo");
+ const expected = "Foo";
+
+ expect(result).toBe(expected);
+});
+```
+
+La implementación mínima sería regresar la cadena que recibe la función, y esto seguiría funcionando para el caso 1.
+
+```ts
+// src/core/camel-case-converter.ts
+export function toCamelCase(string: string) {
+ return string;
+}
+```
+
+No hay nada por refactorizar.
+
+### Caso 3
+
+**3. Debe regresar las palabras unidas en formato `CamelCase` para palabras separadas por espacios con la primera letra en mayúsculas.**
+
+Creamos la prueba:
+
+```ts
+// src/tests/camel-case-converter.test.ts
+it("should return the words joined in CamelCase format for words separated by spaces with the first letter capitalized", () => {
+ const result = toCamelCase("Foo Bar");
+ const expected = "FooBar";
+
+ expect(result).toBe(expected);
+});
+```
+
+La implementación mínima, para no lidiar con expresiones regulares aún, sería separar la cadena utilizando un espacio como separador, y después unir los elementos sin ningún separador.
+
+```ts
+// src/core/camel-case-converter.ts
+export function toCamelCase(string: string) {
+ return string.split(' ').join('');
+}
+```
+
+Las pruebas anteriores seguirían pasando, por supuesto. En esos casos el resultado de separar la cadena sería un arreglo de un solo elemento. Otra vez, no hay nada por refactorizar.
+
+### Caso 4
+
+**4. Debe regresar las palabras unidas en formato `CamelCase` para palabras separadas por guiones con la primera letra en mayúsculas.**
+
+Creamos la prueba:
+
+```ts
+// src/tests/camel-case-converter.test.ts
+it("should return the words joined in CamelCase format for words separated by hyphens with the first letter capitalized", () => {
+ const result = toCamelCase("Foo_Bar-Foo");
+ const expected = "FooBarFoo";
+
+ expect(result).toBe(expected);
+});
+```
+
+La implementación mínima sería, ahora sí, utilizar una expresión regular para separar la cadena por espacios y guiones, ya sean medios o bajos, y después unir los elementos sin ningún separador.
+
+```ts
+// src/core/camel-case-converter.ts
+export function toCamelCase(string: string) {
+ return string.split(/[-_\s]/).join('');
+}
+```
+
+Se usa `\s` en lugar de `' '` por claridad. De nuevo, la refactorización es como el RGB para ser buen programador, no se necesita.
+
+### Caso 5
+
+**5. Debe regresar la palabra con la primera letra en mayúsculas para una palabra con la primera letra en minúsculas.**
+
+Creamos la prueba:
+
+```ts
+// src/tests/camel-case-converter.test.ts
+it("should return the word with the first letter capitalized for a word with the first letter in lowercase", () => {
+ const result = toCamelCase("foo");
+ const expected = "Foo";
+
+ expect(result).toBe(expected);
+});
+```
+
+La implementación mínima aquí sería resolver este problema de la conversión de minúscula a mayúscula para una sola palabra.
+
+```ts
+// src/core/camel-case-converter.ts
+export function toCamelCase(string: string) {
+ const word = string.split(/[-_\s]/).join('');
+ return word.charAt(0).toUpperCase() + word.substring(1);
+}
+```
+
+Primero eliminamos los separadores, unimos de regreso las letras y después convertimos la primera letra a mayúscula y la unimos con el resto de la cadena. De nuevo, no hay nada por refactorizar.
+
+### Caso 6
+
+**6. Debe regresar las palabras unidas en formato `CamelCase` para palabras en minúsculas.**
+
+Llegamos al último caso, ¿qué hay que hacer primero? Crear la prueba:
+
+```ts
+// src/tests/camel-case-converter.test.ts
+it("should return the words joined in CamelCase format for lowercase words", () => {
+ const result = toCamelCase("foo_bar foo");
+ const expected = "FooBarFoo";
+
+ expect(result).toBe(expected);
+});
+```
+
+La implementación mínima que necesitamos parte del caso anterior. Ya sabemos cómo manejar una palabra, entonces solo hay que generalizarlo para la cantidad que sea. Esto es: separar las palabras utilizando los separadores dados, convertir la primera letra de cada una a mayúscula y unirla con el resto de la palabra, y finalmente unir los resultados de cada palabra.
+
+```ts
+// src/core/camel-case-converter.ts
+export function toCamelCase(string: string) {
+ const words = string.split(/[-_\s]/);
+ return words.map((word) => word.charAt(0).toUpperCase() + word.substring(1)).join('');
+}
+```
+
+Aquí, se une todo hasta el final porque no tendría sentido eliminar los separadores, unir los elementos y volver a separar. En este último caso no habría tampoco necesidad de refactorizar.
+
+¡Vualá! Una función más implementada usando TDD. Sí, no se llama magia, aunque a veces lo parece por lo fantástico que llega a ser (mi blog, mis chistes malos).
+
+## Bonus: Otros Casos
+
+Si quieres extender la función para que convierta expresiones que contengan letras mezcladas, habría que convertir todas las letras mayúsculas, que no sean la primera letra de una palabra, a minúscula. Esto se lograría, por ejemplo, con una expresión regular que utilice un `negative lookbehind`. Pensaba simplemente darte el concepto, pero ya que estamos aquí, esta sería la expresión regular:
+
+```ts
+/(? {
+ return match.toLowerCase();
+})
+```
+
+Solo ten en cuenta que, utilizando la configuración de TypeScript de la plantilla, `replaceAll` no es soportado porque la configuración usa `ES5`. Tendrías que cambiarlo por algo como `es2021`:
+
+```json
+// tsconfig.json
+"target": "es2021"
+```
+
+## Enlace al repositorio de GitHub
+
+Puedes encontrar esta kata, y el resto de ellas, [aquí](https://github.com/carlos-talavera/katas-sustainable-testing-ts).
+
+## Conclusión
+
+No te preocupes si este proceso no te parece tan fácil al inicio, repítelo hasta que te quede claro en qué consiste crear software pensando en las pruebas y no en el software en sí. Crea tus propias funciones y pruebas de lo que sea que te interese o te parezca divertido, y poco a poco te hará más sentido. La clave es pensar en **_qué_** tiene que pasar, y naturalmente llegará la implementación que necesitas.
+
+Espero que este otro ejemplo de TDD te sea útil y te ayude a tener una visión más clara de cómo abordar problemas usando este enfoque. Ya sabes, si tienes alguna duda o quieres compartir algo, déjalo en los comentarios :)
\ No newline at end of file