Skip to content

Commit 15bf1f5

Browse files
feat: multi-language support + tests + CI (#1)
* overall restructure + add translations * add github action
1 parent fc1611c commit 15bf1f5

23 files changed

+5259
-165
lines changed

.github/workflows/ci.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: CI & Test
2+
3+
on:
4+
pull_request:
5+
branches: [ main ]
6+
7+
jobs:
8+
test_and_lint:
9+
runs-on: ubuntu-latest
10+
11+
steps:
12+
- uses: actions/checkout@v4
13+
14+
- name: Set up Node.js
15+
uses: actions/setup-node@v4
16+
with:
17+
node-version: '24'
18+
19+
- name: Install dependencies
20+
run: npm ci
21+
22+
- name: Run Jest Tests
23+
run: npm test -- --coverage
24+
25+
- name: Upload Test Coverage Artifact
26+
uses: actions/upload-artifact@v4
27+
with:
28+
name: jest-coverage-report
29+
path: coverage/

.gitignore

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Dependencies
2+
node_modules/
3+
4+
# OS generated files
5+
.DS_Store
6+
Thumbs.db
7+
8+
# IDE files
9+
.vscode/
10+
11+
# Jest/Test Coverage
12+
/coverage/

css/style.css

Lines changed: 0 additions & 160 deletions
This file was deleted.

docs/project-instructions.md

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# Project Instructions - Fernando Tona Portfolio
2+
3+
## Project Overview
4+
5+
This is a **static portfolio website** built with vanilla HTML, CSS, and JavaScript, leveraging Bootstrap 5 for layout. The site features a **custom, lightweight Translation System** that supports English, Spanish, French, and Portuguese. The project is hosted on GitHub Pages at `fernandotonacoder.github.io`.
6+
7+
---
8+
9+
## Architecture & Key Components
10+
11+
### Translation System (`js/translations.js` + `locales/*.json`)
12+
13+
This module manages all text updates, language detection, and metadata application without external libraries.
14+
15+
* **Logic:** Language priority is checked in this order: **Local Storage (key: 'language') → Browser Language → Fallback to English**.
16+
* **Data Structure:** Translations are stored in flat JSON files within the `/locales/` directory (e.g., `en.json`, `role`).
17+
* **HTML Attributes:** Elements are updated using custom `data-translate` attributes:
18+
* `data-translate="key"`: Updates element's **textContent**.
19+
* `data-translate-alt="key"`: Updates the **alt** attribute (essential for images and accessibility).
20+
* `data-translate-html="key"`: Updates **innerHTML** (supported, currently unused).
21+
* **SEO/Metadata:** The system dynamically updates the page `<title>`, `<meta name="description">`, and Open Graph (`og:title`, `og:description`) tags on language change.
22+
* **Performance:** Translations are loaded **asynchronously** (`async/await`) using the native `fetch` API.
23+
24+
### Custom Dropdown (`js/custom-select.js`)
25+
26+
This file implements the styled dropdown menu for language selection.
27+
28+
* **UI Implementation:** Uses vanilla JavaScript to handle dropdown toggle and visual state management (`.open`, `.selected` classes).
29+
* **Integration:** It integrates with the translation system by calling **`setLanguage(lang)`** from `translations.js` upon selection.
30+
* **Language Names:** Display names (e.g., 'English', 'Español') are hardcoded in the `languageNames` object within this file.
31+
32+
### CSS Architecture (`css/style.css`)
33+
34+
The CSS follows a well-organized structure with clear separation of concerns.
35+
36+
* **Color Scheme:** Uses **CSS Variables** defined in `:root` (e.g., `--clr-navy`, `--clr-linkedin`) for easy theme consistency.
37+
* **Icon Styling Pattern:** Icons (SVGs) use CSS filters for color manipulation across different states:
38+
* White icon on dark background: `filter: brightness(0) invert(1)`
39+
* Dark icon on light background: `filter: brightness(0) invert(0)`
40+
* **Visual Pattern:** Elements like the language selector implement a "Glassmorphism" effect using `rgba()` combined with `backdrop-filter: blur(10px)`.
41+
* **Responsiveness:** Mobile-first approach using Bootstrap utility classes and media queries for specific adjustments below 992px and 576px.
42+
43+
---
44+
45+
## Conventions & Development Workflow
46+
47+
### Development Setup
48+
49+
| Task | Detail |
50+
| :--- | :--- |
51+
| **Cross-Platform** | Developed and maintained across **Linux, Windows, and macOS**. |
52+
| **Dependencies** | Requires **Node.js/NPM** to run development tooling (Jest). The core site is dependency-free. |
53+
| **Local Testing** | The project is static: open `index.html` in the browser or use a simple HTTP server. |
54+
| **Deployment** | Git push to the main branch auto-deploys via GitHub Pages. |
55+
| **Version Control** | **`package-lock.json`** must be committed to Git to ensure dependency stability across all environments. |
56+
57+
### Testing
58+
59+
* **Unit Tests:** JavaScript logic (`translations.js`, `custom-select.js`) is validated by `*.test.js` files.
60+
* **Execution:** Tests must be run using **Jest** via the NPM script: `npm test`.
61+
62+
### Adding New Content
63+
64+
* **New Translations:**
65+
1. Add the new key and value to **ALL** locale files (`en.json`, `es.json`, `fr.json`, `pt.json`).
66+
2. Apply the corresponding `data-translate="keyName"` attribute to the target HTML element.
67+
* **New Languages:**
68+
1. Create a new locale file in `/locales/{lang-code}.json` with **all** existing translation keys.
69+
2. Add the language code to the `supportedLangs` array in `js/translations.js`.
70+
3. Add the language name to the `languageNames` object in `js/custom-select.js`.
71+
4. Add the option element to the HTML selector in `index.html`.

jest.config.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
module.exports = {
2+
testEnvironment: 'jsdom',
3+
testMatch: ['**/*.test.js'],
4+
collectCoverageFrom: [
5+
'src/js/**/*.js',
6+
'!src/js/**/*.test.js'
7+
],
8+
coverageDirectory: 'coverage',
9+
verbose: true
10+
};

0 commit comments

Comments
 (0)