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
25 changes: 25 additions & 0 deletions LOCADEX.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# 🌐 Locadex i18n

This repository is configured to use Locadex for automated internationalization.

## Configuration:

- **Working Directory**: `.`
- **Branch Prefix**: `locadex/`
- **Configured Locales**: `en-US`, `fr`
- **Local Translations**: Enabled

## How it works:

- Locadex will automatically analyze your code for translatable content every time you open a PR
- Locadex will modify your build command to automatically generate translations for your content in your configured locales
- Locadex will push its changes to your PR branch, which you can review and merge

## Next Steps:
1. **Get API Keys**: Visit [General Translation Dashboard](https://dash.generaltranslation.com) to generate API Keys
2. **Add API Keys**: Add a Production API Key and Project ID to your project CI workflow to keep your translations up to date
3. In development, using a Development API Key will allow you to hot-reload translations in your app as you make changes

---

Generated by [Locadex](https://generaltranslation.com) • [Documentation](https://generaltranslation.com/docs)
4 changes: 3 additions & 1 deletion app/_hooks/[section]/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import db from '#/lib/db';
import { ClickCounter } from '#/ui/click-counter';
import { Tabs } from '#/ui/tabs';
import { notFound } from 'next/navigation';
import { getGT } from 'gt-next/server';

export default async function Layout({
children,
Expand All @@ -18,14 +19,15 @@ export default async function Layout({
}

const categories = db.category.findMany({ where: { section: section.id } });
const t = await getGT();

return (
<div className="space-y-9">
<div className="flex justify-between">
<Tabs
basePath={`/hooks/${section.slug}`}
items={[
{ text: 'All' },
{ text: t('All') },
...categories.map((x) => ({ text: x.name, slug: x.slug })),
]}
/>
Expand Down
9 changes: 6 additions & 3 deletions app/_hooks/[section]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { HooksClient } from '#/app/_hooks/_components/router-context';
import db from '#/lib/db';
import { notFound } from 'next/navigation';
import { T, Var } from 'gt-next';

export default async function Page({
params,
Expand All @@ -15,9 +16,11 @@ export default async function Page({

return (
<div className="space-y-9">
<h1 className="text-xl font-semibold text-gray-300">
All {section.name}
</h1>
<T>
<h1 className="text-xl font-semibold text-gray-300">
All <Var>{section.name}</Var>
</h1>
</T>

<HooksClient />
</div>
Expand Down
3 changes: 2 additions & 1 deletion app/_hooks/_components/router-context-layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ import {
useSelectedLayoutSegment,
useSelectedLayoutSegments,
} from 'next/navigation';
import { T } from 'gt-next';

export function LayoutHooks() {
const selectedLayoutSegment = useSelectedLayoutSegment();
const selectedLayoutSegments = useSelectedLayoutSegments();

return selectedLayoutSegment ? (
<Boundary label={['Client Component Hooks']} size="small">
<Boundary label={[<T>Client Component Hooks</T>]} size="small">
<div className="overflow-x-auto text-sm text-white [color-scheme:dark]">
<pre>
{JSON.stringify(
Expand Down
4 changes: 3 additions & 1 deletion app/_hooks/_components/router-context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,18 @@ import {
useSelectedLayoutSegment,
useSelectedLayoutSegments,
} from 'next/navigation';
import { useGT } from 'gt-next';

export function HooksClient() {
const pathname = usePathname();
const params = useParams();
const selectedLayoutSegment = useSelectedLayoutSegment();
const selectedLayoutSegments = useSelectedLayoutSegments();
const searchParams = useSearchParams();
const t = useGT();

return (
<Boundary label={['Client Component Hooks']} size="small">
<Boundary label={[t('Client Component Hooks')]} size="small">
<div className="overflow-x-auto text-sm text-white [color-scheme:dark]">
<pre>
{JSON.stringify(
Expand Down
4 changes: 3 additions & 1 deletion app/_hooks/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import db from '#/lib/db';
import { ClickCounter } from '#/ui/click-counter';
import { Tabs } from '#/ui/tabs';
import React from 'react';
import { getGT } from 'gt-next/server';

// export function generateMetadata() {
// const demo = db.demo.find({ where: { slug: 'hooks' } });
Expand All @@ -21,6 +22,7 @@ export default async function Layout({
}: {
children: React.ReactNode;
}) {
const t = await getGT();
const sections = db.section.findMany();

return (
Expand All @@ -29,7 +31,7 @@ export default async function Layout({
<Tabs
basePath="/hooks"
items={[
{ text: 'Home' },
{ text: t('Home') },
...sections.map((x) => ({ text: x.name, slug: x.slug })),
]}
/>
Expand Down
126 changes: 65 additions & 61 deletions app/_internal/_data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,148 +34,152 @@ export type Demo = {

export type DemoCategory = { name: string; items: Demo[] };

const sections: Section[] = [
{ id: '1', name: 'Clothing', slug: 'clothing', categories: ['1', '2', '3'] },
const getSections = (t: (content: string) => string): Section[] => [
{ id: '1', name: t('Clothing'), slug: 'clothing', categories: ['1', '2', '3'] },
{
id: '2',
name: 'Electronics',
name: t('Electronics'),
slug: 'electronics',
categories: ['4', '5', '6'],
},
{ id: '3', name: 'Sports', slug: 'sports', categories: ['7', '8', '9'] },
{ id: '3', name: t('Sports'), slug: 'sports', categories: ['7', '8', '9'] },
];

const categories: Category[] = [
{ id: '1', name: 'Tops', slug: 'tops', section: '1', products: ['1'] },
{ id: '2', name: 'Shorts', slug: 'shorts', section: '1', products: ['2'] },
{ id: '3', name: 'Shoes', slug: 'shoes', section: '1', products: ['3'] },
{ id: '4', name: 'Phones', slug: 'phones', section: '2', products: ['4'] },
{ id: '5', name: 'Laptops', slug: 'laptops', section: '2', products: ['5'] },
{ id: '6', name: 'Tablets', slug: 'tablets', section: '2', products: ['6'] },
{ id: '7', name: 'Balls', slug: 'balls', section: '3', products: ['7'] },
const getCategories = (t: (content: string) => string): Category[] => [
{ id: '1', name: t('Tops'), slug: 'tops', section: '1', products: ['1'] },
{ id: '2', name: t('Shorts'), slug: 'shorts', section: '1', products: ['2'] },
{ id: '3', name: t('Shoes'), slug: 'shoes', section: '1', products: ['3'] },
{ id: '4', name: t('Phones'), slug: 'phones', section: '2', products: ['4'] },
{ id: '5', name: t('Laptops'), slug: 'laptops', section: '2', products: ['5'] },
{ id: '6', name: t('Tablets'), slug: 'tablets', section: '2', products: ['6'] },
{ id: '7', name: t('Balls'), slug: 'balls', section: '3', products: ['7'] },
{
id: '8',
name: 'Equipment',
name: t('Equipment'),
slug: 'equipment',
section: '3',
products: ['8'],
},
{
id: '9',
name: 'Accessories',
name: t('Accessories'),
slug: 'accessories',
section: '3',
products: ['9'],
},
];

const products: Product[] = [
{ id: '1', name: 'Top', image: 'top.png', category: '1' },
{ id: '2', name: 'Shorts', image: 'shorts.png', category: '2' },
{ id: '3', name: 'Shoes', image: 'shoes.png', category: '3' },
const getProducts = (t: (content: string) => string): Product[] => [
{ id: '1', name: t('Top'), image: 'top.png', category: '1' },
{ id: '2', name: t('Shorts'), image: 'shorts.png', category: '2' },
{ id: '3', name: t('Shoes'), image: 'shoes.png', category: '3' },

{ id: '4', name: 'Phone', image: 'phone.png', category: '4' },
{ id: '5', name: 'Laptop', image: 'laptop.png', category: '5' },
{ id: '6', name: 'Tablet', image: 'tablet.png', category: '6' },
{ id: '7', name: 'Basketball', image: 'balls.png', category: '7' },
{ id: '8', name: 'Weights', image: 'weights.png', category: '8' },
{ id: '9', name: 'Gloves', image: 'gloves.png', category: '9' },
{ id: '4', name: t('Phone'), image: 'phone.png', category: '4' },
{ id: '5', name: t('Laptop'), image: 'laptop.png', category: '5' },
{ id: '6', name: t('Tablet'), image: 'tablet.png', category: '6' },
{ id: '7', name: t('Basketball'), image: 'balls.png', category: '7' },
{ id: '8', name: t('Weights'), image: 'weights.png', category: '8' },
{ id: '9', name: t('Gloves'), image: 'gloves.png', category: '9' },
];

const demos = [
const getDemos = (t: (content: string) => string) => [
{
name: 'Layouts',
name: t('Layouts'),
items: [
{
slug: 'layouts',
name: 'Nested Layouts',
description: 'Create UI that is shared across routes',
name: t('Nested Layouts'),
description: t('Create UI that is shared across routes'),
},
{
slug: 'route-groups',
name: 'Route Groups',
description: 'Organize routes without affecting URL paths',
name: t('Route Groups'),
description: t('Organize routes without affecting URL paths'),
},
{
slug: 'parallel-routes',
name: 'Parallel Routes',
description: 'Render multiple pages in the same layout',
name: t('Parallel Routes'),
description: t('Render multiple pages in the same layout'),
},
],
},
{
name: 'File Conventions',
name: t('File Conventions'),
items: [
{
slug: 'loading',
name: 'Loading',
description:
'Create meaningful Loading UI for specific parts of an app',
name: t('Loading'),
description: t('Create meaningful Loading UI for specific parts of an app'),
},
{
slug: 'error',
name: 'Error',
description: 'Create Error UI for specific parts of an app',
name: t('Error'),
description: t('Create Error UI for specific parts of an app'),
},
{
slug: 'not-found',
name: 'Not Found',
description: 'Create Not Found UI for specific parts of an app',
name: t('Not Found'),
description: t('Create Not Found UI for specific parts of an app'),
},
],
},
{
name: 'Caching',
name: t('Caching'),
items: [
{
slug: 'cached-routes',
name: 'Cached Route Segments',
nav_title: 'Cached Routes',
description: 'Cache the rendered output of a route segment',
name: t('Cached Route Segments'),
nav_title: t('Cached Routes'),
description: t('Cache the rendered output of a route segment'),
},
{
slug: 'cached-components',
name: 'Cached React Server Components',
nav_title: 'Cached Components',
description:
'Cache the rendered output of an individual React Server Component',
name: t('Cached React Server Components'),
nav_title: t('Cached Components'),
description: t('Cache the rendered output of an individual React Server Component'),
},
{
slug: 'cached-functions',
name: 'Cached Functions',
description: 'Cache the computed result of a regular function',
name: t('Cached Functions'),
description: t('Cache the computed result of a regular function'),
},
],
},
{
name: 'APIs',
name: t('APIs'),
items: [
{
slug: 'use-link-status',
name: 'useLinkStatus',
description: 'Create inline visual feedback for link interactions',
name: t('useLinkStatus'),
description: t('Create inline visual feedback for link interactions'),
},
],
},
{
name: 'Misc',
name: t('Misc'),
items: [
{
slug: 'view-transitions',
name: 'View Transitions',
description:
'Use animations to help users understand the relationship between the two views',
name: t('View Transitions'),
description: t('Use animations to help users understand the relationship between the two views'),
},
{
slug: 'context',
name: 'Client Context',
description:
'Pass context between Client Components that cross Server/Client Component boundary',
name: t('Client Context'),
description: t('Pass context between Client Components that cross Server/Client Component boundary'),
},
],
},
] as const satisfies DemoCategory[];

const demos = getDemos(() => '');
export type DemoSlug = (typeof demos)[number]['items'][number]['slug'];

export const data = { sections, categories, products, demos };
export const getData = (t: (content: string) => string) => ({
sections: getSections(t),
categories: getCategories(t),
products: getProducts(t),
demos: getDemos(t)
});

export const data = { sections: getSections(() => ''), categories: getCategories(() => ''), products: getProducts(() => ''), demos };
8 changes: 7 additions & 1 deletion app/_patterns/active-links/community/page.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
import { T } from 'gt-next';

export default function Page() {
return <h1 className="text-xl font-bold">Community</h1>;
return (
<T>
<h1 className="text-xl font-bold">Community</h1>
</T>
);
}
14 changes: 8 additions & 6 deletions app/_patterns/active-links/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
import { NavLinks } from '#/app/_patterns/active-links/_components/nav-links';
import Image from 'next/image';
import Link from 'next/link';
import { getGT } from 'gt-next/server';

export default function Layout({ children }: { children: React.ReactNode }) {
export default async function Layout({ children }: { children: React.ReactNode }) {
const t = await getGT();
// Hardcoded links or fetched from db
const links = [
{ href: '/patterns/active-links', name: 'Home' },
{ href: '/patterns/active-links/profile', name: 'Profile' },
{ href: '/patterns/active-links/community', name: 'Community' },
{ href: '/patterns/active-links/settings', name: 'Settings' },
{ href: '/patterns/active-links', name: t('Home') },
{ href: '/patterns/active-links/profile', name: t('Profile') },
{ href: '/patterns/active-links/community', name: t('Community') },
{ href: '/patterns/active-links/settings', name: t('Settings') },
];

return (
Expand All @@ -21,7 +23,7 @@ export default function Layout({ children }: { children: React.ReactNode }) {
className="rounded-full"
width={40}
height={40}
alt="User"
alt={t('User')}
/>
</Link>
</div>
Expand Down
Loading