Skip to content
Open
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
5 changes: 5 additions & 0 deletions .changeset/fine-jeans-beam.md
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Maulik176 there's no need for a patch (it will bump the package version/trigger an NPM release).

Can you please update it to an empty changeset.

Just remove this file and run:

npx changeset --empty

Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"globalonboard": patch
---

Harden onboarding pack export and task editing by escaping user content, converting edited template tasks to custom, and tightening UI defaults.
160 changes: 160 additions & 0 deletions community/global-onboard/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
# GlobalOnboard · LingoHack25 ✨


**One onboarding checklist. Any language. Fully Configurable**
HR writes once in English, and GlobalOnboard turns it into a polished, localized employee experience by combining **Lingo CLI**, **Lingo JavaScript SDK**, and **Lingo CI**.


## 🧠 The MAIN Pillars of GlobalOnboard

- **Real personas:** HR Workspace (authoring) + Employee Experience (preview) wired together in real time.
- **Full Lingo toolchain:** Static JSON via CLI, runtime personalization via SDK, and CI automation so translations stay fresh.
- **Enterprise-ready touches:** Translation QA mode, localization health warnings, onboarding pack export, and translation spinners that prove we’re production aware.

### 🏅 Lingo Product Scorecard

| Lingo product | How GlobalOnboard uses it | Why it matters |
| --- | --- | --- |
| **Lingo CLI** | Generates `data/ui.{locale}.json` and `data/onboarding_template.{locale}.json` from English sources via `npx lingo.dev@latest run`. | Demonstrates the official static localization workflow. |
| **Lingo JavaScript SDK** | Translates the welcome note and every custom task at runtime with caching, spinners, and graceful fallbacks. | Shows dynamic personalization for each employee preview. |
| **Lingo CI** | `.github/workflows/i18n.yml` runs `npx lingo.dev@latest ci --pull-request` whenever English JSON or `i18n.json` changes. | Proves translation automation and GitHub integration end-to-end. |

---

## 🔑 Feature Highlights

| Area | What it unlocks | Lingo capability |
| --- | --- | --- |
| HR Workspace | Edit company, role, welcome note, and a fully dynamic checklist (add/delete/modify tasks). | Authoring surface for English source |
| Employee Experience | Switch between `en`, `es`, `fr`, `hi` previews with live updates + translation loading overlay. | CLI JSON + SDK runtime translations |
| Preview Modes | `Employee view` or `Translation QA` (side-by-side EN vs target locale) with Machine → Edited → Approved overrides. | Human-in-the-loop QA |
| Localization Health | Warns when translated copy is >1.5× English length, per task + summary. | QA signal |
| Onboarding Pack Export | One click generates a `.doc` bundle for the current locale (company, role, tasks, welcome note). | HR enablement |
| Lingo CI Workflow | GitHub Action auto-runs `lingo.dev ci` whenever English JSON changes. | Translation automation |

---

## 🧩 Architecture At-a-Glance

```text
HR inputs ──▶ English JSON templates ──▶ Lingo CLI generates data/ui.{locale}.json
│ │
│ └─▶ Lingo CI keeps translations up to date
├─▶ React state + localStorage overrides
└─▶ Lingo JS SDK
├─ Welcome note runtime translation
└─ Custom task translations (per locale) + caching
```

---

## 🧪 Getting Started (Local Dev)

```bash
git clone https://github.com/lingodotdev/lingo.dev.git
cd lingo.dev/community/global-onboard
npm install

# Provide your API key so CLI + SDK can translate
export LINGO_DOT_DEV_API_KEY="your-key"
# Optional alias used by some shells/CLIs
export LINGODOTDEV_API_KEY="$LINGO_DOT_DEV_API_KEY"

npm run dev
```

Visit **<http://localhost:3000>** — left panel is HR Workspace, right panel is the localized Employee preview.

---

## 🌐 Localization Workflow Cheat Sheet

### 1. Static JSON (Lingo CLI)
- Source files: `data/ui.en.json`, `data/onboarding_template.en.json`
- Configure targets in `i18n.json`
- Generate translations:
```bash
export LINGO_DOT_DEV_API_KEY="your-key"
npx lingo.dev@latest run
```
- CI automation: `.github/workflows/i18n.yml` runs `npx lingo.dev@latest ci --pull-request` on every push to `main` touching English JSON or `i18n.json`.

### 2. Runtime Personalization (Lingo JS SDK)
- Welcome note + any **custom tasks** run through `lib/lingo-client.ts`.
- We cache translations per locale, show a loading spinner overlay, and gracefully fall back to English if the SDK errors.

### 3. Translation QA Mode
- Side-by-side English vs target locale.
- Inline editing with Machine → Edited → Approved chips.
- Reset/Unlock controls to manage overrides.
- Length-based warnings + summary so HR spots risky strings fast.
- Overrides feed every other view (single preview + export).

---

## 📦 Onboarding Pack Export

1. Choose a locale via the Employee panel dropdown.
2. Ensure QA overrides are final (Approved if needed).
3. Click **Download Onboarding Pack** → generates `onboarding-pack-<locale>.doc` with:
- Locale code
- Localized company + role
- Welcome note (SDK translation if non-English)
- Full task list using effective text (overrides or machine)

Perfect for HRIS uploads, emails, or sharing with managers.

---

## 🛠 Tech Stack

- **Next.js 16** (App Router, TypeScript)
- **Tailwind CSS 4** (custom gradient + glassmorphism theme)
- **Lingo.dev CLI, JS SDK, CI**
- **next-themes** + custom design tokens for dark-first UI
- **GitHub Actions** for automated localization runs

---

## 📁 Project Structure

```text
app/
layout.tsx # Root metadata + ThemeProvider
page.tsx # HR + Employee panels, QA, overrides, spinner
globals.css # Tailwind layers + design tokens
components/
mode-toggle.tsx # Shadcn-style theme toggle (hidden by default)
data/
ui.*.json # Static UI translations (CLI managed)
onboarding_template.*.json
lib/
i18n.ts # Typed loaders for JSON bundles
lingo-client.ts # SDK setup + runtime translation helpers
.github/workflows/
i18n.yml # CI job running `lingo.dev ci`
i18n.json # Bucket + locale configuration
```

---

## 🧾 Useful Scripts

- `npm run dev` – Next.js dev server
- `npm run build` – Production build
- `npm run lint` – ESLint via `eslint-config-next`

---

## ✅ Hackathon Compliance & Notes

- All code, UI, and assets created fresh during **LingoHack25**.
- API keys are required only for translation features; none are checked into the repo.
- Want more locales? Add them to `SUPPORTED_LOCALES` + `i18n.json`, re-run the CLI, and you’re done.

---

### 💬 Questions for Judges?
Open an issue or ping me — I'd love to show how GlobalOnboard can become the multilingual onboarding cockpit for any global company.
47 changes: 47 additions & 0 deletions community/global-onboard/app/api/translate/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { NextResponse } from "next/server";

import { translateWithLingo } from "@/lib/lingo";
import { SUPPORTED_LOCALES, type Locale } from "@/lib/i18n";

type TranslationPayload = {
text?: string;
targetLocale?: Locale;
};

const MAX_TEXT_LENGTH = 2000;

export async function POST(request: Request) {
let payload: TranslationPayload;

try {
payload = (await request.json()) as TranslationPayload;
} catch (error) {
console.error("Invalid translation payload", error);
return NextResponse.json({ error: "Invalid request body" }, { status: 400 });
}

const { text, targetLocale } = payload;

if (!text || typeof text !== "string") {
return NextResponse.json({ error: "Missing welcome note" }, { status: 400 });
}

if (text.length > MAX_TEXT_LENGTH) {
return NextResponse.json({ error: "Welcome note is too long" }, { status: 413 });
}

if (!targetLocale || !SUPPORTED_LOCALES.includes(targetLocale)) {
return NextResponse.json({ error: "Unsupported locale" }, { status: 400 });
}

try {
const translated = await translateWithLingo(text, targetLocale);
return NextResponse.json({ translated });
} catch (error) {
console.error("Lingo translation failed", error);
return NextResponse.json(
{ error: "Unable to translate welcome note" },
{ status: 500 },
);
}
}
Binary file added community/global-onboard/app/favicon.ico
Binary file not shown.
43 changes: 43 additions & 0 deletions community/global-onboard/app/globals.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
@import "tailwindcss";

@source "../app/**/*.{js,ts,jsx,tsx}";
@source "../components/**/*.{js,ts,jsx,tsx}";
@source "../lib/**/*.{js,ts,jsx,tsx}";

@custom-variant dark (&:where(.dark, .dark *));

:root {
--background: linear-gradient(135deg, #e3f2ff, #f9f1ff);
--foreground: #0f172a;
--muted: rgba(255, 255, 255, 0.8);
--muted-foreground: #475569;
--panel-start: #eef2ff;
--panel-end: #fdf2f8;
}

.dark {
--background: linear-gradient(145deg, #05010c, #0f172a 55%, #1f2937);
--foreground: #f8fafc;
--muted: rgba(15, 23, 42, 0.85);
--muted-foreground: #94a3b8;
--panel-start: rgba(15, 23, 42, 0.9);
--panel-end: rgba(79, 70, 229, 0.35);
}

@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground);
--font-sans: "Inter", "Sohne", system-ui, -apple-system, blinkmacsystemfont,
"Segoe UI", sans-serif;
--font-mono: "IBM Plex Mono", ui-monospace, "SFMono-Regular", Menlo, monospace;
}

body {
background: var(--background);
color: var(--foreground);
font-family: var(--font-sans);
transition: color 0.3s ease;
background-attachment: fixed;
}
29 changes: 29 additions & 0 deletions community/global-onboard/app/icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
42 changes: 42 additions & 0 deletions community/global-onboard/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import type { Metadata } from "next";
import "./globals.css";
import { ThemeProvider } from "@/components/theme-provider";
import { cn } from "@/lib/utils";

export const metadata: Metadata = {
title: "GlobalOnboard",
description:
"GlobalOnboard lets HR teams create one onboarding checklist and preview it in multiple languages via Lingo.dev.",
icons: {
icon: [
{ url: "/favicon.svg", type: "image/svg+xml" },
{ url: "/favicon.svg", rel: "alternate icon", type: "image/svg+xml" },
],
},
};

export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en" className="dark" suppressHydrationWarning>
<body
className={cn(
"min-h-screen bg-background text-foreground antialiased transition-colors",
)}
>
<ThemeProvider
attribute="class"
defaultTheme="dark"
forcedTheme="dark"
enableSystem={false}
disableTransitionOnChange
>
{children}
</ThemeProvider>
</body>
</html>
);
}
Loading
Loading