From 9f9872376ee2ed82f882b2ed888d8d8fc86efb73 Mon Sep 17 00:00:00 2001 From: Shintaro Jokagi Date: Thu, 29 May 2025 11:53:26 +1200 Subject: [PATCH 01/15] feat(i18n): add japanese translation with better fallback --- astro.config.mjs | 2 +- package.json | 2 +- src/components/BackButton.astro | 10 +- src/components/Button.astro | 16 +- src/components/Community.astro | 20 +- src/components/Features.astro | 26 +- src/components/Hero.astro | 33 +- src/components/ModsList.astro | 587 ++++++++++++++++++ src/components/ModsList.tsx | 236 ------- src/components/ReleaseNoteItem.astro | 3 +- src/components/Sponsors.astro | 2 +- src/components/download/ButtonCard.astro | 15 +- src/components/download/release-data.ts | 82 +-- src/constants/i18n.ts | 22 +- src/constants/index.ts | 2 +- src/hooks/useModsSearch.ts | 172 ----- src/i18n/en/translation.json | 102 +-- src/i18n/ja/translation.json | 514 +++++++++++++++ src/layouts/Layout.astro | 4 +- src/pages/[...locale]/404.astro | 1 + src/pages/[...locale]/download.astro | 2 +- src/pages/[...locale]/mods/[...slug].astro | 22 +- src/pages/[...locale]/mods/index.astro | 8 +- .../[...locale]/release-notes/index.astro | 6 +- src/pages/[...locale]/welcome.astro | 2 +- src/tests/components/release-data.test.ts | 2 +- src/tests/pages/download.spec.ts | 5 +- src/tests/pages/mods.spec.ts | 3 +- src/tests/pages/routes.spec.ts | 2 +- src/utils/i18n.ts | 147 +++-- 30 files changed, 1420 insertions(+), 630 deletions(-) create mode 100644 src/components/ModsList.astro delete mode 100644 src/components/ModsList.tsx delete mode 100644 src/hooks/useModsSearch.ts create mode 100644 src/i18n/ja/translation.json diff --git a/astro.config.mjs b/astro.config.mjs index 40df501..8cc48b5 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -9,7 +9,7 @@ export default defineConfig({ site: 'https://zen-browser.app', i18n: { defaultLocale: 'en', - locales: ['en'], + locales: ['en', 'ja'], routing: { fallbackType: 'rewrite', prefixDefaultLocale: false, diff --git a/package.json b/package.json index d4f56ae..9e4b93b 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,7 @@ "prepare": "husky", "test": "npx vitest run", "test:coverage": "npx vitest --coverage", - "test:playwright": "npx playwright test" + "test:playwright": "npx playwright test --reporter=list" }, "dependencies": { "@astrojs/check": "^0.9.4", diff --git a/src/components/BackButton.astro b/src/components/BackButton.astro index 8b6816f..5004ae9 100644 --- a/src/components/BackButton.astro +++ b/src/components/BackButton.astro @@ -9,9 +9,15 @@ const { mods: { slug }, }, } = getUI(locale) + +const { href, ...props } = Astro.props + +if (!href) { + console.error('BackButton: href is required') +} --- - + diff --git a/src/components/Button.astro b/src/components/Button.astro index e2266ed..9967220 100644 --- a/src/components/Button.astro +++ b/src/components/Button.astro @@ -3,7 +3,17 @@ import { getLocale, getPath } from '~/utils/i18n' const locale = getLocale(Astro) const getLocalePath = getPath(locale) -const { class: className, isPrimary, isAlert, isBordered, href, id, extra } = Astro.props +const { + class: className, + isPrimary, + isAlert, + isBordered, + href, + id, + extra, + localePath = true, + ...props +} = Astro.props --- { @@ -11,7 +21,7 @@ const { class: className, isPrimary, isAlert, isBordered, href, id, extra } = As @@ -41,6 +52,7 @@ const { class: className, isPrimary, isAlert, isBordered, href, id, extra } = As ? '' : '!transition-bg border-2 border-dark hover:bg-dark hover:text-paper hover:shadow-sm', ]} + {...props} > diff --git a/src/components/Community.astro b/src/components/Community.astro index 0bc2a5e..89d38e6 100644 --- a/src/components/Community.astro +++ b/src/components/Community.astro @@ -23,15 +23,17 @@ const { class="relative flex w-full flex-col items-center gap-6 py-12 text-start md:text-center lg:py-36" > - - {community.title[0]} - - - {community.title[1]} - - - {community.title[2]} - + { + community.title.map((title, index) => + title !== '\n' ? ( + + {title} + + ) : ( + + ) + ) + } {community.description} diff --git a/src/components/Features.astro b/src/components/Features.astro index fb753d8..171876e 100644 --- a/src/components/Features.astro +++ b/src/components/Features.astro @@ -19,22 +19,28 @@ const { }, } = getUI(locale) -const { title1 = features.title1, title2 = features.title2, title3 = features.title3 } = Astro.props +interface Props { + titles?: string[] +} + +const { titles } = Astro.props const descriptions = Object.values(features.featureTabs).map(tab => tab.description) ---
- - {title1} - - - {title2} - - - {title3} - + { + (titles || features.titles).map((title, index) => + title !== '\n' ? ( + + {title} + + ) : ( + + ) + ) + } {features.description} diff --git a/src/components/Hero.astro b/src/components/Hero.astro index cf77f2b..3bc9a6d 100644 --- a/src/components/Hero.astro +++ b/src/components/Hero.astro @@ -37,26 +37,25 @@ const { >
- <motion.span client:load {...getHeroTitleAnimation()}> - {hero.title[0]} - </motion.span> - <motion.span client:load {...getHeroTitleAnimation()}> - {hero.title[1]} - </motion.span> - <br class="hidden md:block" /> - <motion.span client:load {...getHeroTitleAnimation()}> - {hero.title[2]} - </motion.span> - <motion.span client:load {...getHeroTitleAnimation()} className="italic text-coral"> - {hero.title[3]} - </motion.span> - <motion.span client:load {...getHeroTitleAnimation()}> - {hero.title[4]} - </motion.span> + { + hero.title.map(title => + title.text !== '\n' ? ( + <motion.span + client:load + {...getHeroTitleAnimation()} + className={title.highlight ? 'italic text-coral' : ''} + > + {title.text} + </motion.span> + ) : ( + <br class="hidden md:block" /> + ) + ) + } - {hero.description[0]}. + {hero.description[0]} {hero.description[1]} diff --git a/src/components/ModsList.astro b/src/components/ModsList.astro new file mode 100644 index 0000000..cbda6da --- /dev/null +++ b/src/components/ModsList.astro @@ -0,0 +1,587 @@ +--- +import { icon, library } from '@fortawesome/fontawesome-svg-core' +import { faSort, faSortDown, faSortUp } from '@fortawesome/free-solid-svg-icons' +import { type ZenTheme } from '~/mods' +import { getPath, type Locale } from '~/utils/i18n' + +// Add icons to the library +library.add(faSort, faSortUp, faSortDown) + +// Create icon objects +const defaultSortIcon = icon({ prefix: 'fas', iconName: 'sort' }) +const ascSortIcon = icon({ prefix: 'fas', iconName: 'sort-up' }) +const descSortIcon = icon({ prefix: 'fas', iconName: 'sort-down' }) + +interface ModsListProps { + allMods: ZenTheme[] + locale: Locale + // eslint-disable-next-line @typescript-eslint/no-explicit-any + translations: any +} + +const { allMods, locale, translations } = Astro.props as ModsListProps + +const getLocalePath = getPath(locale) + +// Server-side rendering setup +const defaultLimit = 12 +const defaultPage = 1 +const initialMods = allMods.slice(0, defaultLimit) +const totalPages = Math.ceil(allMods.length / defaultLimit) +--- + +
+
+
+ +
+ +
+
+ +
+ +
+ +
+ +
+ + +
+
+
+ + + +
+ + diff --git a/src/components/ModsList.tsx b/src/components/ModsList.tsx deleted file mode 100644 index d388a76..0000000 --- a/src/components/ModsList.tsx +++ /dev/null @@ -1,236 +0,0 @@ -import { icon, library } from '@fortawesome/fontawesome-svg-core' -import { faSort, faSortDown, faSortUp } from '@fortawesome/free-solid-svg-icons' -import { useEffect, useState, type FormEvent } from 'react' - -import { useModsSearch } from '~/hooks/useModsSearch' -import { type ZenTheme } from '~/mods' -import { getUI, type Locale } from '~/utils/i18n' - -// Add icons to the library -library.add(faSort, faSortUp, faSortDown) - -// Create icon objects -const defaultSortIcon = icon({ prefix: 'fas', iconName: 'sort' }) -const ascSortIcon = icon({ prefix: 'fas', iconName: 'sort-up' }) -const descSortIcon = icon({ prefix: 'fas', iconName: 'sort-down' }) - -type ModsListProps = { - allMods: ZenTheme[] - locale: Locale -} - -const ModsList = ({ allMods, locale }: ModsListProps) => { - const { - search, - createdSort, - updatedSort, - page, - limit, - totalPages, - totalItems, - setSearch, - toggleCreatedSort, - toggleUpdatedSort, - setPage, - setLimit, - mods: paginatedMods, - // searchParams, - } = useModsSearch(allMods) - - const [pageInput, setPageInput] = useState(page.toString()) - - // Keep page input in sync with actual page - useEffect(() => { - setPageInput(page.toString()) - }, [page]) - - function getSortIcon(state: 'default' | 'asc' | 'desc') { - if (state === 'asc') return ascSortIcon - if (state === 'desc') return descSortIcon - return defaultSortIcon - } - - function handleSearch(e: FormEvent) { - const target = e.target as HTMLInputElement - setSearch(target.value) - } - - function handleLimitChange(e: FormEvent) { - const target = e.target as HTMLSelectElement - setLimit(Number.parseInt(target.value, 10)) - } - - function handlePageSubmit(e: FormEvent) { - e.preventDefault() - const newPage = Number.parseInt(pageInput, 10) - if (!Number.isNaN(newPage) && newPage >= 1 && newPage <= totalPages) { - setPage(newPage) - window.scrollTo(0, 0) - } else { - setPageInput(page.toString()) - } - } - - function handlePageInputChange(e: FormEvent) { - const target = e.target as HTMLInputElement - setPageInput(target.value) - } - - function navigatePage(pageNum: number) { - setPage(pageNum) - window.scrollTo(0, 0) - } - - const { - routes: { mods }, - } = getUI(locale) - - function renderPagination() { - if (totalPages <= 1) return null - return ( -
- -
- {mods.pagination.pagination.split('{input}').map((value, index) => { - if (index === 0) { - return ( - - ) - } - return ( - - {value - .replace('{totalPages}', totalPages.toString()) - .replace('{totalItems}', totalItems.toString())} - - ) - })} -
- -
- ) - } - - return ( -
-
-
- -
- -
-
- -
- -
- -
- -
- - -
-
-
- -
- {paginatedMods.length > 0 ? ( - paginatedMods.map(mod => ( - -
- {mod.name} -
-
-

- {mod.name} by @{mod.author} -

-

{mod.description}

-
-
- )) - ) : ( -
-

{mods.noResults}

-

{mods.noResultsDescription}

-
- )} -
- - {renderPagination()} -
- ) -} - -export default ModsList diff --git a/src/components/ReleaseNoteItem.astro b/src/components/ReleaseNoteItem.astro index 5906dee..3f967d2 100644 --- a/src/components/ReleaseNoteItem.astro +++ b/src/components/ReleaseNoteItem.astro @@ -1,6 +1,7 @@ --- import InfoIcon from '~/icons/InfoIcon.astro' +import { getIntlLocale } from '~/constants/i18n' import { releaseNotes as releaseNotesData } from '~/release-notes' import { getLocale, getPath, getUI } from '~/utils/i18n' import { type ReleaseNote, getReleaseNoteFirefoxVersion } from '../release-notes' @@ -184,7 +185,7 @@ generateItems(props.knownIssues, 'known') }
- {date && date.toLocaleDateString('en-US', { dateStyle: 'long' })} + {date && date.toLocaleDateString(getIntlLocale(locale), { dateStyle: 'long' })}
{ diff --git a/src/components/Sponsors.astro b/src/components/Sponsors.astro index 95b9f19..d54d3d1 100644 --- a/src/components/Sponsors.astro +++ b/src/components/Sponsors.astro @@ -21,7 +21,7 @@ const {
- Our Sponsors + {sponsors.title} diff --git a/src/components/download/ButtonCard.astro b/src/components/download/ButtonCard.astro index 81df8ec..15b59df 100644 --- a/src/components/download/ButtonCard.astro +++ b/src/components/download/ButtonCard.astro @@ -1,4 +1,13 @@ --- +import { getLocale, getUI } from '~/utils/i18n' + +const locale = getLocale(Astro) +const { + routes: { + download: { buttonCard }, + }, +} = getUI(locale) + interface Props { label: string href: string @@ -42,7 +51,7 @@ const { label, href, checksum } = Astro.props @@ -62,7 +71,7 @@ const { label, href, checksum } = Astro.props - Beta + {buttonCard.beta}
mapping filenames to SHA-256 hashes */ -export function getReleasesWithChecksums(checksums: Record) { - return { - macos: { - universal: { - link: 'https://github.com/zen-browser/desktop/releases/latest/download/zen.macos-universal.dmg', - label: 'Universal', - checksum: checksums['zen.macos-universal.dmg'], +export function getReleasesWithChecksums(locale: string) { + const { + routes: { + download: { + links: { macos, windows, linux }, }, }, - windows: { - x86_64: { - link: 'https://github.com/zen-browser/desktop/releases/latest/download/zen.installer.exe', - label: '64-bit (Recommended)', - checksum: checksums['zen.installer.exe'], - }, - arm64: { - link: 'https://github.com/zen-browser/desktop/releases/latest/download/zen.installer-arm64.exe', - label: 'ARM64', - checksum: checksums['zen.installer-arm64.exe'], - }, - }, - linux: { - x86_64: { - tarball: { - link: 'https://github.com/zen-browser/desktop/releases/latest/download/zen.linux-x86_64.tar.xz', - label: 'Tarball', - checksum: checksums['zen.linux-x86_64.tar.xz'], + } = getUI(locale) + return (checksums: Record) => { + return { + macos: { + universal: { + link: 'https://github.com/zen-browser/desktop/releases/latest/download/zen.macos-universal.dmg', + label: macos.universal, + checksum: checksums['zen.macos-universal.dmg'], }, }, - aarch64: { - tarball: { - link: 'https://github.com/zen-browser/desktop/releases/latest/download/zen.linux-aarch64.tar.xz', - label: 'Tarball', - checksum: checksums['zen.linux-aarch64.tar.xz'], + windows: { + x86_64: { + link: 'https://github.com/zen-browser/desktop/releases/latest/download/zen.installer.exe', + label: windows['64bit'], + checksum: checksums['zen.installer.exe'], + }, + arm64: { + link: 'https://github.com/zen-browser/desktop/releases/latest/download/zen.installer-arm64.exe', + label: windows.ARM64, + checksum: checksums['zen.installer-arm64.exe'], }, }, - flathub: { - all: { - link: 'https://flathub.org/apps/app.zen_browser.zen', - label: 'Flathub', + linux: { + x86_64: { + tarball: { + link: 'https://github.com/zen-browser/desktop/releases/latest/download/zen.linux-x86_64.tar.xz', + label: linux.x86_64, + checksum: checksums['zen.linux-x86_64.tar.xz'], + }, + }, + aarch64: { + tarball: { + link: 'https://github.com/zen-browser/desktop/releases/latest/download/zen.linux-aarch64.tar.xz', + label: linux.aarch64, + checksum: checksums['zen.linux-aarch64.tar.xz'], + }, + }, + flathub: { + all: { + link: 'https://flathub.org/apps/app.zen_browser.zen', + label: linux.flathub, + }, }, }, - }, + } } } diff --git a/src/constants/i18n.ts b/src/constants/i18n.ts index cfb486b..d89a7a4 100644 --- a/src/constants/i18n.ts +++ b/src/constants/i18n.ts @@ -1,4 +1,20 @@ -export const I18N = { +const UI_EN = (await import('~/i18n/en/translation.json', { with: { type: 'json' } })).default +const UI_JA = (await import('~/i18n/ja/translation.json', { with: { type: 'json' } })).default + +export const i18n = { DEFAULT_LOCALE: 'en', - LOCALES: [{ label: 'English', value: 'en' }], -} as const + LOCALES: [ + { label: 'English', value: 'en', ui: UI_EN, intl: 'en-US' }, + { label: '日本語', value: 'ja', ui: UI_JA, intl: 'ja-JP' }, + ], +} + +/** + * Type definition for UI translations based on the English translation + * @typedef {Object} UIProps + */ +export type UIProps = typeof UI_EN | typeof UI_JA + +export const getIntlLocale = (locale: string) => { + return i18n.LOCALES.find(l => l.value === locale)?.intl +} diff --git a/src/constants/index.ts b/src/constants/index.ts index e38ca40..717f6c0 100644 --- a/src/constants/index.ts +++ b/src/constants/index.ts @@ -1,5 +1,5 @@ import { CHECKSUMS } from './checksum' -import { I18N } from './i18n' +import { i18n as I18N } from './i18n' export const CONSTANT = { I18N, diff --git a/src/hooks/useModsSearch.ts b/src/hooks/useModsSearch.ts deleted file mode 100644 index 9fd8882..0000000 --- a/src/hooks/useModsSearch.ts +++ /dev/null @@ -1,172 +0,0 @@ -import { useEffect, useState } from 'react' - -import { type ZenTheme } from '../mods' - -type SortOrder = 'default' | 'asc' | 'desc' - -type ModsSearchState = { - search: string - createdSort: SortOrder - updatedSort: SortOrder - page: number - limit: number -} - -const DEFAULT_LIMIT = 12 - -export function useModsSearch(mods: ZenTheme[]) { - const [searchParams, setSearchParams] = useState() - const [state, setState] = useState({ - search: '', - createdSort: 'desc', - updatedSort: 'default', - page: 1, - limit: DEFAULT_LIMIT, - }) - - // Initialize search params - useEffect(() => { - const params = new URLSearchParams(window.location.search) - setSearchParams(params) - setState({ - search: params.get('q') || '', - createdSort: (params.get('created') as SortOrder) || 'desc', - updatedSort: (params.get('updated') as SortOrder) || 'default', - page: Number.parseInt(params.get('page') || '1', 10), - limit: Number.parseInt(params.get('limit') || String(DEFAULT_LIMIT), 10), - }) - }, []) - - // Update URL when state changes - useEffect(() => { - if (!searchParams) return - - if (state.search) { - searchParams.set('q', state.search) - } else { - searchParams.delete('q') - } - - if (state.createdSort !== 'default') { - searchParams.set('created', state.createdSort) - } else { - searchParams.delete('created') - } - - if (state.updatedSort !== 'default') { - searchParams.set('updated', state.updatedSort) - } else { - searchParams.delete('updated') - } - - if (state.page > 1) { - searchParams.set('page', state.page.toString()) - } else { - searchParams.delete('page') - } - - if (state.limit !== DEFAULT_LIMIT) { - searchParams.set('limit', state.limit.toString()) - } else { - searchParams.delete('limit') - } - - const newUrl = `${window.location.pathname}${searchParams.toString() ? `?${searchParams.toString()}` : ''}` - - if (state.page > 1) { - window.history.pushState({}, '', newUrl) - } else { - window.history.replaceState({}, '', newUrl) - } - }, [state, searchParams]) - - const filteredMods = (() => { - let filtered = [...mods] - - // Filter by search - const searchTerm = state.search.toLowerCase() - if (searchTerm) { - filtered = filtered.filter( - mod => - mod.name.toLowerCase().includes(searchTerm) || - mod.description.toLowerCase().includes(searchTerm) || - mod.author.toLowerCase().includes(searchTerm) || - (mod.tags?.some(tag => tag.toLowerCase().includes(searchTerm)) ?? false) - ) - } - - // Sort by createdAt if chosen - if (state.createdSort !== 'default') { - filtered.sort((a, b) => { - const diff = new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime() - return state.createdSort === 'asc' ? diff : -diff - }) - } - - // Sort by updatedAt if chosen - if (state.updatedSort !== 'default') { - filtered.sort((a, b) => { - const diff = new Date(a.updatedAt).getTime() - new Date(b.updatedAt).getTime() - return state.updatedSort === 'asc' ? diff : -diff - }) - } - - return filtered - })() - - // Calculate pagination - const totalPages = Math.ceil(filteredMods.length / state.limit) - const startIndex = (state.page - 1) * state.limit - const endIndex = startIndex + state.limit - const paginatedMods = filteredMods.slice(startIndex, endIndex) - - const setSearch = (search: string) => { - setState(prev => ({ ...prev, search, page: 1 })) // Reset page when search changes - } - - const toggleCreatedSort = () => { - setState(prev => ({ - ...prev, - createdSort: - prev.createdSort === 'default' ? 'asc' : prev.createdSort === 'asc' ? 'desc' : 'default', - page: 1, // Reset page when sort changes - })) - } - - const toggleUpdatedSort = () => { - setState(prev => ({ - ...prev, - updatedSort: - prev.updatedSort === 'default' ? 'asc' : prev.updatedSort === 'asc' ? 'desc' : 'default', - page: 1, // Reset page when sort changes - })) - } - - const setPage = (page: number) => { - setState(prev => ({ - ...prev, - page: Math.max(1, Math.min(page, totalPages)), - })) - } - - const setLimit = (limit: number) => { - setState(prev => ({ ...prev, limit, page: 1 })) // Reset page when limit changes - } - - return { - search: state.search, - createdSort: state.createdSort, - updatedSort: state.updatedSort, - page: state.page, - limit: state.limit, - totalPages, - totalItems: filteredMods.length, - setSearch, - toggleCreatedSort, - toggleUpdatedSort, - setPage, - setLimit, - mods: paginatedMods, - searchParams, - } -} diff --git a/src/i18n/en/translation.json b/src/i18n/en/translation.json index fa0cda0..f71b629 100644 --- a/src/i18n/en/translation.json +++ b/src/i18n/en/translation.json @@ -3,7 +3,14 @@ "index": { "title": "Zen Browser", "hero": { - "title": ["welcome", "to", "a", "calmer", "internet"], + "title": [ + { "text": "welcome ", "highlight": false }, + { "text": "to ", "highlight": false }, + { "text": "\n", "highlight": false }, + { "text": "a ", "highlight": false }, + { "text": "calmer ", "highlight": true }, + { "text": "internet", "highlight": false } + ], "description": [ "Beautifully designed, privacy-focused, and packed with features.", "We care about your experience, not your data." @@ -14,10 +21,8 @@ } }, "features": { - "title1": "Productivity", - "title2": "at", - "title3": "its best", - "description": "Zen Browser is packed with features that help you stay productive and focused. Browsers should be tools that help you get things done, not distractions that keep you from your work.", + "titles": ["Productivity ", "at ", "its best"], + "description": "Zen is packed with features that help you stay productive and focused. Browsers should be tools that help you get things done, not distractions that keep you from your work.", "featureTabs": { "workspaces": { "title": "Workspaces", @@ -48,7 +53,7 @@ } }, "community": { - "title": ["Our", "Core", "Values"], + "title": ["Our ", "Core ", "Values"], "description": "We make it not only a priority, but a necessity to ensure that Zen always strikes the right balance between beauty, performance, and privacy. We are committed to making Zen the most beautiful, productive, and privacy-respecting browser out there — without compromising on your experience.", "lists": { "freeAndOpenSource": { @@ -102,9 +107,8 @@ } }, "releaseNotes": { - "title": "Release notes - Zen Browser", "topSection": { - "title": "Release Notes", + "title": "Changelog", "description": "Stay up to date with the latest changes to Zen! Since the first release till {latestVersion}, we've been working hard to make Zen Browser the best it can be. Thanks everyone for your feedback! ❤️" }, "list": { @@ -256,25 +260,25 @@ } }, "download": { - "title": "Download - Zen Browser", - "description": "Download Zen Browser for your platform and experience a more mindful internet browsing experience. All downloads include SHA256 checksums for verification.", + "title": "Download Zen", + "description": "Download Zen for your platform and experience a more mindful internet browsing experience. All downloads include SHA256 checksums for verification.", "twilightInfo": "You're currently in Twilight mode, this means you're downloading the latest experimental features and updates.", "alertInfo": { "description": "Twilight Mode: You're currently in Twilight mode, this means you're downloading the latest experimental features and updates." }, "platformSelector": { "title": "Platform Selector", - "description": "Select your platform to download Zen Browser." + "description": "Select your platform to download Zen." }, "additionalResources": { "title": "Additional Resources", "sourceCode": { "title": "Source Code", - "description": "Explore Zen Browser's source code on GitHub. Contribute to the project or build your own version." + "description": "Explore Zen's source code on GitHub. Contribute to the project or build your own version." }, "documentation": { "title": "Documentation", - "description": "Access comprehensive documentation, guides, and tutorials for Zen Browser." + "description": "Access comprehensive documentation, guides, and tutorials for Zen." } }, "securityNotice": { @@ -293,6 +297,20 @@ "mac": "Works on both new Apple (M-Series) and older Intel Macs.
Requires macOS 11.0 or later.", "windows": "Works on Windows 10 and Windows 11.
Not sure which version to get? Most people should choose the 64-bit installer.", "linux": "Works with many Linux versions.
Pick the download that matches your system." + }, + "links": { + "macos": { "universal": "Universal" }, + "windows": { "64bit": "64-bit (Recommended)", "ARM64": "ARM64" }, + "linux": { + "flathub": "Flathub", + "x86_64": "Tarball", + "aarch64": "Tarball" + } + }, + "buttonCard": { + "copy": "Copy", + "showChecksum": "Show SHA-256", + "beta": "Beta" } }, "privacyPolicy": { @@ -301,97 +319,97 @@ "sections": { "introduction": { "title": "Introduction", - "body": "Welcome to Zen Browser! Your privacy is our priority. This Privacy Policy outlines the types of personal information we collect, how we use it, and the steps we take to protect your data when you use Zen Browser.", + "body": "Welcome to Zen! Your privacy is our priority. This Privacy Policy outlines the types of personal information we collect, how we use it, and the steps we take to protect your data when you use Zen.", "summary": "We don't sell data - We don't collect data - We don't track you" }, "noCollect": { "title": "1. Information We Do Not Collect", - "body": "Zen Browser is designed with privacy in mind. We do not collect, store, or share any of your personal data. Here's what that means:" + "body": "Zen is designed with privacy in mind. We do not collect, store, or share any of your personal data. Here's what that means:" }, "noTelemetry": { "title": "1.1. No Telemetry", "body": "We do not collect any telemetry data or crash reports.", - "body2": "Zen Browser has stripped out telemetry built into Mozilla Firefox. We have removed all telemetry data collection and crash reports." + "body2": "Zen has stripped out telemetry built into Mozilla Firefox. We have removed all telemetry data collection and crash reports." }, "noPersonalData": { "title": "1.2. No Personal Data Collection", - "body": "Zen Browser does not collect any personal information such as your IP address, browsing history, search queries, or form data." + "body": "Zen does not collect any personal information such as your IP address, browsing history, search queries, or form data." }, "noThirdParty": { "title": "1.3. No Third-Party Tracking", - "body": "We do not allow third-party trackers or analytics tools to operate within Zen Browser. Your browsing activity remains entirely private and is not shared with any third party. Mozilla is not considered a third party as it is the base of Zen Browser." + "body": "We do not allow third-party trackers or analytics tools to operate within Zen. Your browsing activity remains entirely private and is not shared with any third party. Mozilla is not considered a third party as it is the base of Zen." }, "externalConnections": { "title": "1.4. External connections made at startup", - "body": "Zen Browser may make external connections at startup to check for updates and ensure the browser is up to date on plugins, addons, check for connectivity and Geolocation/push notifications services in order to comply with web standards. We, at Zen, do not collect any data from these connections, but they may be logged by third-party services or websites you visit. These connections are necessary for the proper functioning of the browser and are not used for tracking or profiling purposes. They can be disabled through the browser flags (about:config)." + "body": "Zen may make external connections at startup to check for updates and ensure the browser is up to date on plugins, addons, check for connectivity and Geolocation/push notifications services in order to comply with web standards. We, at Zen, do not collect any data from these connections, but they may be logged by third-party services or websites you visit. These connections are necessary for the proper functioning of the browser and are not used for tracking or profiling purposes. They can be disabled through the browser flags (about:config)." }, "localStorage": { "title": "2. Information Stored Locally on Your Device" }, "browsingData": { "title": "2.1. Browsing Data", - "body": "Zen Browser stores certain data locally on your device to enhance your browsing experience. This includes:" + "body": "Zen stores certain data locally on your device to enhance your browsing experience. This includes:" }, "cookies": { "title": "Cookies", - "body": "Cookies are stored locally on your device and are not shared with Zen Browser or any third party. You have full control over the management of cookies through the browser's settings." + "body": "Cookies are stored locally on your device and are not shared with Zen or any third party. You have full control over the management of cookies through the browser's settings." }, "cache": { "title": "Cache and Temporary Files", - "body": "Zen Browser may store cache files and other temporary data locally to improve performance. These files can be cleared at any time through the browser's settings." + "body": "Zen may store cache files and other temporary data locally to improve performance. These files can be cleared at any time through the browser's settings." }, "settings": { "title": "2.2. Settings and Preferences", - "body": "Any customizations, settings, and preferences you make within Zen Browser are stored locally on your device. We do not have access to or control over this data." + "body": "Any customizations, settings, and preferences you make within Zen are stored locally on your device. We do not have access to or control over this data." }, "sync": { "title": "3. Sync Feature", - "body": "Zen Browser offers a \"Sync\" feature, which is implemented using Mozilla Firefox's Sync feature. This feature allows you to synchronize your bookmarks, history, passwords, and other data across multiple devices. For this feature to work, your data is encrypted and stored on Mozilla's servers and is treated in accordance with their Privacy Policy. We, at Zen, cannot view any of this data.", + "body": "Zen offers a \"Sync\" feature, which is implemented using Mozilla Firefox's Sync feature. This feature allows you to synchronize your bookmarks, history, passwords, and other data across multiple devices. For this feature to work, your data is encrypted and stored on Mozilla's servers and is treated in accordance with their Privacy Policy. We, at Zen, cannot view any of this data.", "link1": "Mozilla Firefox Sync", "link2": "This is how we store your passwords" }, "addons": { "title": "4. Add-ons and \"Mods\"", - "body": "You can install Add-ons from addons.mozilla.org. Zen Browser periodically checks for updates to these Add-ons.\nYou can also install \"Mods\" from zen-browser.app/mods. These Mods are hosted by our services and follow the same privacy policy our website. We do not collect any data from these Mods, they are purely static content that is downloaded to your device." + "body": "You can install Add-ons from addons.mozilla.org. Zen periodically checks for updates to these Add-ons.\nYou can also install \"Mods\" from zen-browser.app/mods. These Mods are hosted by our services and follow the same privacy policy our website. We do not collect any data from these Mods, they are purely static content that is downloaded to your device." }, "security": { "title": "5. Data Security", - "body": "Although Zen Browser does not collect your data, we are committed to protecting the information that is stored locally on your device and, if you use the Sync feature, the encrypted data stored on Mozilla's servers. We recommend that you use secure passwords, enable device encryption, and regularly update your software to ensure your data remains safe.", + "body": "Although Zen does not collect your data, we are committed to protecting the information that is stored locally on your device and, if you use the Sync feature, the encrypted data stored on Mozilla's servers. We recommend that you use secure passwords, enable device encryption, and regularly update your software to ensure your data remains safe.", "note": "Note that most of the security measures are taken care by Mozilla Firefox." }, "control": { "title": "6. Your Control", "deletionTitle": "6.1. Data Deletion", - "deletionBody": "You have full control over all data stored locally on your device by Zen Browser. You can clear your browsing data, cookies, and cache at any time using the browser's settings." + "deletionBody": "You have full control over all data stored locally on your device by Zen. You can clear your browsing data, cookies, and cache at any time using the browser's settings." }, "website": { "title": "7. Our Website and Services", - "body": "Zen Browser's website and services do not use any third-party analytics, tracking, or CDN services. We do not collect any personal information from users visiting our website. The website is hosted on Cloudflare but with analytics and tracking disabled, Cloudflare may collect some analytics data from HTTP requests in order to provide security and performance improvements. However, this data is not linked to any personal information and is not used for tracking purposes.", + "body": "Zen's website and services do not use any third-party analytics, tracking, or CDN services. We do not collect any personal information from users visiting our website. The website is hosted on Cloudflare but with analytics and tracking disabled, Cloudflare may collect some analytics data from HTTP requests in order to provide security and performance improvements. However, this data is not linked to any personal information and is not used for tracking purposes.", "externalLinksTitle": "7.1. External links", - "externalLinksBody": "Zen Browser may contain links to external websites or services that are not owned or operated by us. We are not responsible for the content or privacy practices of these sites. We recommend that you review the privacy policies of these sites before providing them with any personal information." + "externalLinksBody": "Zen may contain links to external websites or services that are not owned or operated by us. We are not responsible for the content or privacy practices of these sites. We recommend that you review the privacy policies of these sites before providing them with any personal information." }, "changes": { "title": "8. Changes to This Privacy Policy", - "body": "We may update this Privacy Policy from time to time to reflect changes in our practices or legal requirements. We will notify you of any significant changes by updating the effective date at the top of this policy. Continued use of Zen Browser after such changes constitutes your acceptance of the new terms." + "body": "We may update this Privacy Policy from time to time to reflect changes in our practices or legal requirements. We will notify you of any significant changes by updating the effective date at the top of this policy. Continued use of Zen after such changes constitutes your acceptance of the new terms." }, "otherTelemetry": { "title": "9. Other telemetry done by Mozilla Firefox", - "body": "We try to disable all telemetry data collection in Zen Browser. But, we may have missed some. Check the below links for more information.", + "body": "We try to disable all telemetry data collection in Zen. But, we may have missed some. Check the below links for more information.", "firefoxPrivacyNotice": "Firefox Privacy Notice", "forMoreInformation": "for more information." }, "contact": { "title": "10. Contact Us", - "body": "If you have any questions or concerns about this Privacy Policy or Zen Browser, please contact us at:", + "body": "If you have any questions or concerns about this Privacy Policy or Zen, please contact us at:", "discord": "Discord: ", - "discordLink": "Zen Browser's Discord", + "discordLink": "Zen's Discord", "github": "GitHub: ", "githubLink": "Organization" } } }, "welcome": { - "title": ["Welcome", "to", "Zen!"] + "title": ["Welcome ", "to ", "Zen!"] }, "whatsNew": { "title": "What's New in {latestVersion.version}!", @@ -412,11 +430,11 @@ }, "mods": { "title": "Zen Mods", - "description": "Browse our diverse collection of Zen Mods, community-made plugins and themes for Zen Browser. Discover a theme to match every mood, and a plugin to fulfill every requirement. Start customizing your browser experience today!" + "description": "Browse our diverse collection of Zen Mods, community-made plugins and themes for Zen. Discover a theme to match every mood, and a plugin to fulfill every requirement. Start customizing your browser experience today!" }, "releaseNotes": { "title": "Release notes - Zen", - "description": "Stay up to date with the latest changes to Zen Browser! Since the first release till {latestVersion}, we've been working hard to make Zen Browser the best it can be. Thanks everyone for your feedback! ❤️" + "description": "Stay up to date with the latest changes to Zen! Since the first release till {latestVersion}, we've been working hard to make Zen the best it can be. Thanks everyone for your feedback! ❤️" }, "about": { "title": "About Zen", @@ -428,11 +446,11 @@ }, "download": { "title": "Download - Zen", - "description": "Download Zen Browser for your platform and experience a more mindful internet browsing experience. All downloads include SHA256 checksums for verification." + "description": "Download Zen for your platform and experience a more mindful internet browsing experience. All downloads include SHA256 checksums for verification." }, "privacyPolicy": { "title": "Privacy Policy - Zen", - "description": "Your privacy is our priority. This Privacy Policy outlines the types of personal information we collect, how we use it, and the steps we take to protect your data when you use Zen Browser." + "description": "Your privacy is our priority. This Privacy Policy outlines the types of personal information we collect, how we use it, and the steps we take to protect your data when you use Zen." }, "welcome": { "title": "Welcome!", @@ -477,13 +495,13 @@ "releaseNotesDesc": "Stay up to date with the latest features and improvements.", "discordDesc": "Join our community on Discord to chat with other Zen users!", "donate": "Donate ❤️", - "donateDesc": "Support the development of Zen Browser with a donation.", + "donateDesc": "Support the development of Zen with a donation.", "aboutUs": "About Us 🌟", - "aboutUsDesc": "Learn more about the team behind Zen Browser.", + "aboutUsDesc": "Learn more about the team behind Zen.", "documentation": "Documentation", - "documentationDesc": "Learn how to use Zen Browser with our documentation.", + "documentationDesc": "Learn how to use Zen with our documentation.", "github": "GitHub", - "githubDesc": "Contribute to the development of Zen Browser on GitHub.", + "githubDesc": "Contribute to the development of Zen on GitHub.", "menu": "Menu" } } diff --git a/src/i18n/ja/translation.json b/src/i18n/ja/translation.json new file mode 100644 index 0000000..f41b59d --- /dev/null +++ b/src/i18n/ja/translation.json @@ -0,0 +1,514 @@ +{ + "routes": { + "index": { + "title": "Zenブラウザー", + "hero": { + "title": [ + { "text": "ようこそ", "highlight": false }, + { "text": "\n", "highlight": false }, + { "text": "静かな", "highlight": true }, + { "text": "\n", "highlight": false }, + { "text": "インターネット", "highlight": false }, + { "text": "へ", "highlight": false } + ], + "description": [ + "美しいデザイン、プライバシー重視、機能満載。", + "私たちはあなたの体験を大切にし、データには関心がありません。" + ], + "buttons": { + "beta": "ベータ版が利用可能です!", + "support": "サポートする ❤️" + } + }, + "features": { + "titles": ["生産性", "の", "極み"], + "description": "Zenは、生産性と集中力を高める機能が満載です。ブラウザーは作業の妨げではなく、作業を助けるツールであるべきです。", + "featureTabs": { + "workspaces": { + "title": "ワークスペース", + "description": "タブをワークスペースごとに整理し、プロジェクトごとに分けて管理。簡単に切り替え可能です。" + }, + "compactMode": { + "title": "コンパクトモード", + "description": "Zenのコンパクトモードは、必要ないときにタブバーを隠し、必要なときに表示して画面を広く使えます。" + }, + "glance": { + "title": "覗き見", + "description": "覗き見機能で、よく使うタブを素早く切り替え。履歴をスクロールする必要はありません。" + }, + "splitView": { + "title": "画面分割", + "description": "画面分割機能で、2つのタブを並べて表示。比較や切り替えが簡単です。" + } + } + }, + "sponsors": { + "title": "スポンサー", + "description": "ご支援いただいているスポンサーの皆様に感謝します。
あなたも直接寄付でこの旅に参加できます!", + "sponsors": { + "tuta": { + "name": "Tuta", + "url": "https://tuta.com/" + } + } + }, + "community": { + "title": ["私たちの", "コア", "バリュー"], + "description": "Zenは美しさ、パフォーマンス、プライバシーのバランスを最優先にしています。最高の体験を妥協せずに提供します。", + "lists": { + "freeAndOpenSource": { + "title": "無料・オープンソース", + "description": "Zenは無料でオープンソース。誰でも自由に使え、カスタマイズできます。" + }, + "simpleYetPowerful": { + "title": "シンプルでパワフル", + "description": "Zenは使いやすく、日常の作業も十分にこなせます。" + }, + "privateAndAlwaysUpToDate": { + "title": "プライバシー重視・常に最新", + "description": "Zenはプライバシーを守り、常に最新。無料で使え、カスタマイズも可能です。" + } + }, + "images": { + "community": { + "alt": "コミュニティ" + } + } + } + }, + "mods": { + "title": "Zen Mods", + "description": "Zen Browser用の多彩なMod(プラグイン・テーマ)を探そう。気分やニーズに合ったテーマやプラグインで、ブラウザー体験をカスタマイズ!", + "pagination": { + "pagination": "{input} / {totalPages}(全{totalItems}件)" + }, + "search": "検索ワードを入力...", + "sort": { + "lastCreated": "新着順", + "lastUpdated": "更新順", + "perPage": "表示件数" + }, + "noResults": "結果が見つかりません", + "noResultsDescription": "別のキーワードで検索するか、後でもう一度お試しください。", + "slug": { + "title": "{name} - Zen Mods", + "description": "{name} Modの詳細(Zen用)", + "alert": { + "description": "このテーマをインストールするにはZenが必要です。", + "button": "今すぐダウンロード!" + }, + "createdBy": "作成者:{author}v{version}", + "creationDate": "作成日 • {createdAt}", + "latestUpdate": "最終更新 • {updatedAt}", + "visitModHomepage": "Modのホームページへ", + "installMod": "Modをインストール 🎉", + "uninstallMod": "Modをアンインストール", + "back": "戻る" + } + }, + "releaseNotes": { + "topSection": { + "title": "変更履歴", + "description": "Zenの最新情報はこちら!最初のリリースから{latestVersion}まで、最高のブラウザーを目指して努力しています。ご意見ありがとうございます!❤️" + }, + "list": { + "support": "応援してください!", + "navigateToVersion": "バージョンへ移動..." + }, + "itemType": { + "fix": "修正", + "feature": "追加", + "known": "既知", + "break": "重大", + "theme": "テーマ", + "security": "セキュリティ" + }, + "backToTop": "トップへ戻る", + "chooseVersion": "バージョンを選択", + "components": { + "releaseNoteItem": { + "twilight": "Twilight", + "twilightChanges": "Twilightの変更点", + "releaseChanges": "v{version}", + "firefoxVersion": "Firefox {version}", + "githubRelease": "GitHubリリース", + "workflowRun": "ワークフロー実行", + "compareChanges": "変更を比較", + "twilightWarning": "TwilightはZen Browserのプレリリース版です。不具合や未完成の機能が含まれる場合があります。", + "reportIssues": " 問題が発生した場合は、issueページでご報告ください。", + "learnMore": "詳細はこちら", + "viewIssue": "GitHubのIssue番号{issue}を見る" + } + }, + "slug": { + "title": "リリースノート", + "redirect": "バージョン{version}のリリースノートにリダイレクト中..." + } + }, + "about": { + "title": "Zenについて", + "description": "私たちは、ウェブ体験を大切にする開発者とデザイナーの集まりです。インターネットは、データ収集を心配せずに探索・学習・交流できる場所であるべきだと信じています。", + "littleHelp": "応援しませんか?", + "mainTeam": { + "title": "メインチーム", + "description": "最高のブラウジング体験を提供するために努力しているメンバーです。", + "subTitle": { + "browser": "ブラウザー", + "website": "ウェブサイト・ブランディング" + }, + "members": { + "browser": { + "mauro": { + "name": "Mauro B.", + "description": "クリエイター・メイン開発者", + "link": "https://cheff.dev/" + }, + "jan": { + "name": "Jan Heres", + "description": "MacOSビルド担当・貢献者", + "link": "https://janheres.eu/" + }, + "bryan": { + "name": "Bryan Galdámez", + "description": "テーマ機能の大貢献者", + "link": "https://josuegalre.netlify.app/" + }, + "oscar": { + "name": "Oscar Gonzalez", + "description": "SRE・コード署名担当", + "link": false + }, + "daniel": { + "name": "Daniel García", + "description": "MacOS証明書・公証管理", + "link": false + }, + "brhm": { + "name": "BrhmDev", + "description": "大きな貢献をしている開発者", + "link": "https://github.com/BrhmDev" + }, + "kristijanribaric": { + "name": "Kristijan Ribaric", + "description": "スプリットビュー・ワークスペース担当", + "link": "https://github.com/kristijanribaric" + }, + "larvey": { + "name": "Larvey", + "description": "AUR管理者", + "link": "https://github.com/LarveyOfficial/" + }, + "studio": { + "name": "Studio Movie Girl", + "description": "グラデーションジェネレーターの貢献者", + "link": "https://github.com/neurokitti" + } + }, + "website": { + "taroj1205": { + "name": "Shintaro Jokagi", + "description": "コアウェブサイトアーキテクト、リファクタリング・技術強化担当", + "link": "https://github.com/taroj1205" + }, + "jace": { + "name": "Jace", + "description": "ウェブサイトデザイン・ブランディング担当", + "link": "https://x.com/JaceThings" + }, + "canoa": { + "name": "Canoa", + "description": "活発な貢献者・ウェブサイト管理", + "link": "https://thatcanoa.org/" + }, + "adam": { + "name": "Adam", + "description": "ブランディング・デザイン", + "link": "https://cybrneon.xyz/" + }, + "n7itro": { + "name": "n7itro", + "description": "リリースノート執筆・貢献者", + "link": "https://github.com/n7itro" + }, + "jafeth": { + "name": "Jafeth Garro", + "description": "ドキュメント執筆", + "link": "https://iamjafeth.com/" + } + } + } + }, + "contributors": { + "title": "コントリビューター", + "description": "Zenの発展に貢献してくださった皆様です。", + "browser": "ブラウザー", + "website": "ウェブサイト" + } + }, + "donate": { + "title": "寄付", + "description": "私たちは少人数の開発チームです。ご支援いただけると幸いです。", + "patreon": { + "title": "Patreon", + "description": "Patreonで毎月のご支援が可能です。ご自身に合った支援レベルをお選びください。", + "button": "Patreonへ" + }, + "koFi": { + "title": "Ko-fi", + "description": "Ko-fiで一度きり、または毎月のご支援が可能です。ご希望の金額をお選びください。", + "button": "Ko-fiへ" + } + }, + "download": { + "title": "Zenをダウンロードする", + "description": "お使いのプラットフォーム向けにZenをダウンロード。すべてのダウンロードにはSHA256チェックサムが付属しています。", + "twilightInfo": "現在Twilightモードです。最新の実験的機能とアップデートをダウンロードしています。", + "alertInfo": { + "description": "Twilightモード: 現在Twilightモードで、最新の実験的機能とアップデートをダウンロードしています。" + }, + "platformSelector": { + "title": "プラットフォーム選択", + "description": "お使いのプラットフォームを選択してZenをダウンロード。" + }, + "additionalResources": { + "title": "追加リソース", + "sourceCode": { + "title": "ソースコード", + "description": "GitHubでZenのソースコードを閲覧・貢献・ビルドできます。" + }, + "documentation": { + "title": "ドキュメント", + "description": "Zenの包括的なドキュメント・ガイド・チュートリアル。" + } + }, + "securityNotice": { + "title": "検証済み・安全なダウンロード", + "description": "すべてのZenダウンロードは署名・検証済みです。公式サイトまたはGitHubからのダウンロードを推奨します。ダウンロードに問題がある場合やウイルス対策で警告が出た場合は、ご報告ください。" + }, + "platformNames": { + "mac": "macOS", + "windows": "Windows", + "linux": "Linux", + "macDownload": "MacOSダウンロード", + "windowsDownload": "Windowsダウンロード", + "linuxDownload": "Linuxダウンロード" + }, + "platformDescriptions": { + "mac": "Apple(Mシリーズ)・Intel両対応。
macOS 11.0以降が必要です。", + "windows": "Windows 10・11対応。
どちらを選ぶか迷った場合は64ビット版を推奨します。", + "linux": "多くのLinuxディストリビューションで動作。
お使いのシステムに合ったものを選択してください。" + }, + "links": { + "macos": { + "universal": "ユニバーサル" + }, + "windows": { + "64bit": "64-ビット(推奨)", + "ARM64": "ARM64" + }, + "linux": { + "flathub": "Flathub", + "x86_64": "Tarball", + "aarch64": "Tarball" + } + }, + "buttonCard": { + "copy": "コピー", + "showChecksum": "SHA-256を表示", + "beta": "ベータ" + } + }, + "privacyPolicy": { + "title": "プライバシーポリシー", + "lastUpdated": "最終更新: 2025-02-5", + "sections": { + "introduction": { + "title": "はじめに", + "body": "Zenへようこそ!あなたのプライバシーは最優先です。本ポリシーでは、収集する情報の種類、利用方法、保護手段について説明します。", + "summary": "データ販売なし - データ収集なし - トラッキングなし" + }, + "noCollect": { + "title": "1. 収集しない情報", + "body": "Zenはプライバシー重視で設計されています。個人データを収集・保存・共有しません。" + }, + "noTelemetry": { + "title": "1.1. テレメトリーなし", + "body": "テレメトリーデータやクラッシュレポートは収集しません。", + "body2": "Mozilla Firefoxに組み込まれているテレメトリーも削除しています。" + }, + "noPersonalData": { + "title": "1.2. 個人データの収集なし", + "body": "IPアドレス、閲覧履歴、検索クエリ、フォームデータなどの個人情報は一切収集しません。" + }, + "noThirdParty": { + "title": "1.3. サードパーティトラッキングなし", + "body": "サードパーティのトラッカーや解析ツールは一切許可していません。Mozillaはベースであり、サードパーティではありません。" + }, + "externalConnections": { + "title": "1.4. 起動時の外部接続", + "body": "Zenは起動時にアップデート確認や接続性・ジオロケーション/プッシュ通知サービスのため外部接続を行う場合があります。これらの接続は機能上必要で、トラッキングやプロファイリング目的ではありません。about:configで無効化可能です。" + }, + "localStorage": { + "title": "2. デバイスに保存される情報" + }, + "browsingData": { + "title": "2.1. 閲覧データ", + "body": "Zenは体験向上のため、いくつかのデータをローカルに保存します。" + }, + "cookies": { + "title": "クッキー", + "body": "クッキーはローカルに保存され、Zenや第三者と共有されません。管理はブラウザー設定から可能です。" + }, + "cache": { + "title": "キャッシュ・一時ファイル", + "body": "パフォーマンス向上のためキャッシュや一時データを保存します。設定からいつでも削除可能です。" + }, + "settings": { + "title": "2.2. 設定・プリファレンス", + "body": "カスタマイズや設定はすべてローカルに保存され、私たちがアクセスすることはありません。" + }, + "sync": { + "title": "3. 同期機能", + "body": "ZenはMozilla FirefoxのSync機能を利用しています。データは暗号化されMozillaのサーバーに保存されます。私たちは内容を閲覧できません。", + "link1": "Mozilla Firefox Sync", + "link2": "パスワードの保存方法" + }, + "addons": { + "title": "4. アドオン・Mod", + "body": "MozillaのアドオンやZen Modsをインストール可能です。Zen Modsは当社サービスでホストされ、データ収集はありません。" + }, + "security": { + "title": "5. データセキュリティ", + "body": "Zenはデータを収集しませんが、ローカルやMozillaサーバー上のデータ保護に努めています。安全なパスワードやデバイス暗号化、ソフトウェアの定期更新を推奨します。", + "note": "多くのセキュリティ対策はMozilla Firefoxによって提供されています。" + }, + "control": { + "title": "6. コントロール", + "deletionTitle": "6.1. データ削除", + "deletionBody": "Zenが保存するすべてのローカルデータは、設定からいつでも削除できます。" + }, + "website": { + "title": "7. ウェブサイト・サービス", + "body": "Zenのウェブサイト・サービスはサードパーティの解析やCDNを使用しません。Cloudflareでホストされていますが、解析・トラッキングは無効化されています。", + "externalLinksTitle": "7.1. 外部リンク", + "externalLinksBody": "Zenには外部サイトへのリンクが含まれる場合があります。内容やプライバシーについては各サイトのポリシーをご確認ください。" + }, + "changes": { + "title": "8. ポリシーの変更", + "body": "本ポリシーは必要に応じて更新されます。重要な変更時は日付を更新し、継続利用で同意したものとみなします。" + }, + "otherTelemetry": { + "title": "9. Mozilla Firefoxによるその他のテレメトリー", + "body": "すべてのテレメトリー無効化に努めていますが、見落としがある場合もあります。詳細は下記リンクをご参照ください。", + "firefoxPrivacyNotice": "Firefoxプライバシー通知", + "forMoreInformation": "詳細はこちら。" + }, + "contact": { + "title": "10. お問い合わせ", + "body": "本ポリシーやZenに関するご質問は下記までご連絡ください:", + "discord": "Discord: ", + "discordLink": "ZenのDiscord", + "github": "GitHub: ", + "githubLink": "Organization" + } + } + }, + "welcome": { + "title": ["ようこそ", "Zenへ", "!"] + }, + "whatsNew": { + "title": "{latestVersion.version}の新機能!", + "reportIssue": "問題を報告する", + "joinDiscord": "Discordに参加", + "readFullReleaseNotes": "リリースノート全文を読む" + }, + "notFound": { + "title": "ページが見つかりません", + "description": "お探しのページは存在しないか、移動されました。", + "button": "ホームへ戻る" + } + }, + "layout": { + "index": { + "title": "Zenブラウザー", + "description": "美しいデザイン、プライバシー重視、機能満載。" + }, + "mods": { + "title": "Zen Mods", + "description": "Zen用の多彩なMod(プラグイン・テーマ)を探そう。気分やニーズに合ったテーマやプラグインで、ブラウザ体験をカスタマイズ!" + }, + "releaseNotes": { + "title": "リリースノート - Zen", + "description": "Zenの最新情報はこちら!最初のリリースから{latestVersion}まで、最高のブラウザを目指して努力しています。ご意見ありがとうございます!❤️" + }, + "about": { + "title": "Zenについて", + "description": "私たちは、ウェブ体験を大切にする開発者とデザイナーの集まりです。インターネットは、データ収集を心配せずに探索・学習・交流できる場所であるべきだと信じています。" + }, + "donate": { + "title": "寄付 - Zen", + "description": "私たちは少人数の開発チームです。ご支援いただけると幸いです。" + }, + "download": { + "title": "Zenをダウンロードする", + "description": "お使いのプラットフォーム向けにZenをダウンロード。すべてのダウンロードにはSHA256チェックサムが付属しています。" + }, + "privacyPolicy": { + "title": "プライバシーポリシー - Zen", + "description": "あなたのプライバシーは最優先です。本ポリシーでは、収集する情報の種類、利用方法、保護手段について説明します。" + }, + "welcome": { + "title": "ようこそ!", + "description": "Zenへようこそ!" + }, + "whatsNew": { + "title": "{latestVersion.version}の新機能!" + } + }, + "components": { + "footer": { + "title": "Zenブラウザー", + "description": "美しいデザイン、プライバシー重視、機能満載。私たちはあなたのデータではなく、体験を大切にします。", + "download": "ダウンロード", + "followUs": "フォローする", + "aboutUs": "私たちについて", + "teamAndContributors": "チーム・コントリビューター", + "privacyPolicy": "プライバシーポリシー", + "getStarted": "はじめに", + "documentation": "ドキュメント", + "zenMods": "Zen Mods", + "releaseNotes": "リリースノート", + "getHelp": "ヘルプ", + "discord": "Discord", + "uptimeStatus": "稼働状況", + "reportAnIssue": "問題を報告", + "twilight": "Twilight", + "madeWith": "❤️と共にZenチームが作りました" + }, + "nav": { + "brand": "Zenブラウザー", + "menu": { + "gettingStarted": "はじめに", + "usefulLinks": "便利なリンク", + "mods": "Mods", + "download": "ダウンロード", + "discord": "Discord", + "releaseNotes": "リリースノート", + "zenMods": "Zen Mods", + "tryZenMods": "Zen Modsを試す", + "zenModsDesc": "Zen Modsでブラウザ体験をカスタマイズ。", + "releaseNotesDesc": "最新機能・改善情報はこちら。", + "discordDesc": "Discordコミュニティで他のZenユーザーと交流!", + "donate": "寄付 ❤️", + "donateDesc": "Zen開発を寄付で応援。", + "aboutUs": "私たちについて 🌟", + "aboutUsDesc": "Zenのチームについて知る。", + "documentation": "ドキュメント", + "documentationDesc": "ドキュメントでZenの使い方を学ぶ。", + "github": "GitHub", + "githubDesc": "GitHubでZen開発に貢献。", + "menu": "メニュー" + } + } + } +} diff --git a/src/layouts/Layout.astro b/src/layouts/Layout.astro index 8e56381..f717917 100644 --- a/src/layouts/Layout.astro +++ b/src/layouts/Layout.astro @@ -97,7 +97,9 @@ const locale = getLocale(Astro) ) - +
diff --git a/src/pages/[...locale]/404.astro b/src/pages/[...locale]/404.astro index 230f788..cfcbc65 100644 --- a/src/pages/[...locale]/404.astro +++ b/src/pages/[...locale]/404.astro @@ -7,6 +7,7 @@ import { getLocale, getPath, getUI } from '~/utils/i18n' export { getStaticPaths } from '~/utils/i18n' const locale = getLocale(Astro) +console.log(Astro.currentLocale) const getLocalePath = getPath(locale) const { routes: { notFound }, diff --git a/src/pages/[...locale]/download.astro b/src/pages/[...locale]/download.astro index 8a9775c..5524548 100644 --- a/src/pages/[...locale]/download.astro +++ b/src/pages/[...locale]/download.astro @@ -27,7 +27,7 @@ const appleIcon = icon({ prefix: 'fab', iconName: 'apple' }) const githubIcon = icon({ prefix: 'fab', iconName: 'github' }) const checksums = await getChecksums() -const releases = getReleasesWithChecksums(checksums) +const releases = getReleasesWithChecksums(locale)(checksums) const platformNames = download.platformNames const platformDescriptions = download.platformDescriptions diff --git a/src/pages/[...locale]/mods/[...slug].astro b/src/pages/[...locale]/mods/[...slug].astro index 445e257..660ca3a 100644 --- a/src/pages/[...locale]/mods/[...slug].astro +++ b/src/pages/[...locale]/mods/[...slug].astro @@ -6,7 +6,7 @@ import ArrowRightIcon from '~/icons/ArrowRightIcon.astro' import InfoIcon from '~/icons/InfoIcon.astro' import Layout from '~/layouts/Layout.astro' import { getAllMods, getAuthorLink, getLocalizedDate } from '~/mods' -import { getUI } from '~/utils/i18n' +import { getPath, getUI } from '~/utils/i18n' import { getLocale, getOtherLocales } from '~/utils/i18n' export async function getStaticPaths() { @@ -44,7 +44,9 @@ const dates = { updatedAt: getLocalizedDate(mod.updatedAt), } -const locale = getLocale(Astro as { params: { locale?: string } }) +const locale = getLocale(Astro) + +const getLocalePath = getPath(locale) const { routes: { @@ -58,8 +60,8 @@ const { description={slug.description.replace('{name}', mod.name)} ogImage={mod.image} > -
-
+
+
- +
{mod.name} {mod.description} @@ -132,3 +134,13 @@ const {
+ + diff --git a/src/pages/[...locale]/mods/index.astro b/src/pages/[...locale]/mods/index.astro index 1404c55..bbfd548 100644 --- a/src/pages/[...locale]/mods/index.astro +++ b/src/pages/[...locale]/mods/index.astro @@ -1,6 +1,6 @@ --- import Description from '~/components/Description.astro' -import ModsList from '~/components/ModsList' +import ModsList from '~/components/ModsList.astro' import { CONSTANT } from '~/constants' import Layout from '~/layouts/Layout.astro' import { getAllMods } from '~/mods' @@ -27,6 +27,10 @@ const allMods = (await getAllMods()) || [] - +
diff --git a/src/pages/[...locale]/release-notes/index.astro b/src/pages/[...locale]/release-notes/index.astro index e24900e..77cc542 100644 --- a/src/pages/[...locale]/release-notes/index.astro +++ b/src/pages/[...locale]/release-notes/index.astro @@ -22,7 +22,7 @@ const { class="container flex h-full min-h-[1000px] flex-1 flex-col items-center justify-center py-4" >
- Changelog + {releaseNotes.topSection.title}

{releaseNotes.list.support} -

@@ -46,7 +46,7 @@ const { {releaseNotesData.map(notes => )}
-