Skip to content

Commit

Permalink
separate files for translations
Browse files Browse the repository at this point in the history
  • Loading branch information
Shane Osbourne committed Jul 1, 2024
1 parent 3ff4a2e commit 224260d
Show file tree
Hide file tree
Showing 32 changed files with 14,315 additions and 126 deletions.
523 changes: 523 additions & 0 deletions build/app/locales/bg.json

Large diffs are not rendered by default.

523 changes: 523 additions & 0 deletions build/app/locales/cs.json

Large diffs are not rendered by default.

523 changes: 523 additions & 0 deletions build/app/locales/da.json

Large diffs are not rendered by default.

523 changes: 523 additions & 0 deletions build/app/locales/de.json

Large diffs are not rendered by default.

523 changes: 523 additions & 0 deletions build/app/locales/el.json

Large diffs are not rendered by default.

599 changes: 599 additions & 0 deletions build/app/locales/en.json

Large diffs are not rendered by default.

523 changes: 523 additions & 0 deletions build/app/locales/es.json

Large diffs are not rendered by default.

523 changes: 523 additions & 0 deletions build/app/locales/et.json

Large diffs are not rendered by default.

523 changes: 523 additions & 0 deletions build/app/locales/fi.json

Large diffs are not rendered by default.

523 changes: 523 additions & 0 deletions build/app/locales/fr.json

Large diffs are not rendered by default.

523 changes: 523 additions & 0 deletions build/app/locales/hr.json

Large diffs are not rendered by default.

523 changes: 523 additions & 0 deletions build/app/locales/hu.json

Large diffs are not rendered by default.

523 changes: 523 additions & 0 deletions build/app/locales/it.json

Large diffs are not rendered by default.

523 changes: 523 additions & 0 deletions build/app/locales/lt.json

Large diffs are not rendered by default.

523 changes: 523 additions & 0 deletions build/app/locales/lv.json

Large diffs are not rendered by default.

523 changes: 523 additions & 0 deletions build/app/locales/nb.json

Large diffs are not rendered by default.

523 changes: 523 additions & 0 deletions build/app/locales/nl.json

Large diffs are not rendered by default.

523 changes: 523 additions & 0 deletions build/app/locales/pl.json

Large diffs are not rendered by default.

523 changes: 523 additions & 0 deletions build/app/locales/pt.json

Large diffs are not rendered by default.

523 changes: 523 additions & 0 deletions build/app/locales/ro.json

Large diffs are not rendered by default.

523 changes: 523 additions & 0 deletions build/app/locales/ru.json

Large diffs are not rendered by default.

523 changes: 523 additions & 0 deletions build/app/locales/sk.json

Large diffs are not rendered by default.

523 changes: 523 additions & 0 deletions build/app/locales/sl.json

Large diffs are not rendered by default.

523 changes: 523 additions & 0 deletions build/app/locales/sv.json

Large diffs are not rendered by default.

523 changes: 523 additions & 0 deletions build/app/locales/tr.json

Large diffs are not rendered by default.

1,093 changes: 1,003 additions & 90 deletions build/app/public/js/base.js

Large diffs are not rendered by default.

5 changes: 5 additions & 0 deletions scripts/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,11 @@ console.time('copy')
execSync('node scripts/copy.mjs', { cwd: BASE, stdio: 'inherit', env })
console.timeEnd('copy')

// copy assets
console.time('translations')
execSync('node scripts/locale.mjs', { cwd: BASE, stdio: 'inherit', env })
console.timeEnd('translations')

// bundle
console.time('bundle')
execSync('node scripts/bundle.mjs', { cwd: BASE, stdio: 'inherit', env })
Expand Down
73 changes: 73 additions & 0 deletions scripts/locale.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import fs from 'fs'
import path from 'path'
import { mkdirSync } from 'node:fs'
import { dirname, join } from 'node:path'
import { cwd } from './utils.mjs'
import z from 'zod'

const CWD = cwd(import.meta.url)
const BASE = join(CWD, '..')
const LOCALES_BASE = join(BASE, 'shared/locales')

const env = z
.object({
BUILD_OUTPUT: z.string(),
NODE_ENV: z.union([z.literal('production'), z.literal('development')]).default('production'),
})
.parse(process.env)

// const IS_PROD = env.NODE_ENV === 'production'
const OUTPUT_DIR = join(BASE, env.BUILD_OUTPUT, 'locales')

// Function to read JSON file and return its contents as an object
function readJSONFile(filePath) {
try {
const data = fs.readFileSync(filePath, 'utf8')
return JSON.parse(data)
} catch (err) {
console.error(`Error reading file ${filePath}:`, err)
return null
}
}

// Function to create a combined JSON file for a locale directory
function createLocaleFile(localePath, locale) {
const result = {}
const files = fs.readdirSync(localePath)

files.forEach((file) => {
const filePath = path.join(localePath, file)
if (fs.statSync(filePath).isFile() && file.endsWith('.json')) {
const fileName = path.basename(file, '.json')
const json = readJSONFile(filePath)
delete json.smartling
Object.values(json).forEach((value) => {
try {
delete value.note
} catch (e) {
//
}
})
result[fileName] = json
}
})

let output = path.join(OUTPUT_DIR, `${locale}.json`)
mkdirSync(dirname(output), { recursive: true })
fs.writeFileSync(output, JSON.stringify(result, null, 2), 'utf8')
console.log(`✅ Created ${output}`)
}

// Function to traverse the locales directory and process each locale
function processLocales() {
const locales = fs.readdirSync(LOCALES_BASE)

locales.forEach((locale) => {
const localePath = path.join(LOCALES_BASE, locale)
if (fs.statSync(localePath).isDirectory()) {
createLocaleFile(localePath, locale)
}
})
}

processLocales()
49 changes: 29 additions & 20 deletions shared/js/ui/base/localize.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,32 @@
import i18next from 'i18next'
import ICU from 'i18next-icu'
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import siteTranslations from '../../../locales/en/site.json'
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import reportTranslations from '../../../locales/en/report.json'
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import toggleReportTranslations from '../../../locales/en/toggle-report.json'
import connection from '../../../locales/en/connection.json'
import ctascreens from '../../../locales/en/ctascreens.json'
import firebutton from '../../../locales/en/firebutton.json'
import permissions from '../../../locales/en/permissions.json'
import report from '../../../locales/en/report.json'
import shared from '../../../locales/en/shared.json'
import site from '../../../locales/en/site.json'
import toggleReport from '../../../locales/en/toggle-report.json'

// @ts-ignore
import localeResources from '../../../locales/*/*.json'
const resources = {
connection,
ctascreens,
firebutton,
permissions,
report,
shared,
site,
'toggle-report': toggleReport,
}

i18next.use(ICU).init({
// debug: true,
initImmediate: false,
fallbackLng: 'en',
lng: 'en',
ns: ['shared', 'site', 'connection', 'report', 'ctascreens', 'firebutton', 'toggle-report'],
defaultNS: 'shared',
resources: localeResources,
ns: Object.keys(resources),
resources: { en: resources },
i18nFormat: {
parseErrorHandler: (err, key, res, options) => {
console.warn('parseErrorHandler', err, key, res, options)
Expand All @@ -29,39 +38,39 @@ export const i18n = i18next

/**
* A helper for accessing the 'site' namespace with a bit of help from Typescript
* @template {keyof siteTranslations} K
* @template {keyof site} K
* @template {`${K}.${string}`} F
* @param {F} key
* @param {Record<string, any>} [options]
*/
function site(key, options) {
function siteT(key, options) {
return i18next.t(`site:${key}`, options)
}

/**
* A helper for accessing the 'report' namespace with a bit of help from Typescript
* @template {keyof reportTranslations} K
* @template {keyof report} K
* @template {`${K}.${string}`} F
* @param {F} key
* @param {Record<string, any>} [options]
*/
function report(key, options) {
function reportT(key, options) {
return i18next.t(`report:${key}`, options)
}

/**
* A helper for accessing the 'report' namespace with a bit of help from Typescript
* @template {keyof toggleReportTranslations} K
* @template {keyof toggleReport} K
* @template {`${K}.title`} F
* @param {F} key
* @param {Record<string, any>} [options]
*/
function toggleReport(key, options) {
function toggleReportT(key, options) {
return i18next.t(`toggle-report:${key}`, options)
}

export const ns = {
site,
report,
toggleReport,
site: siteT,
report: reportT,
toggleReport: toggleReportT,
}
16 changes: 1 addition & 15 deletions v2/data-provider.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import { h, createContext } from 'preact'
import comms, { platform } from '../shared/js/browser/communication.js'
import { useCallback, useContext, useEffect, useState } from 'preact/hooks'
import { i18n } from '../shared/js/ui/base/localize'
import { useCallback, useEffect, useState } from 'preact/hooks'
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import { createPlatformFeatures, FeatureSettings, PlatformFeatures } from '../shared/js/ui/platform-features.mjs'
import {
Expand Down Expand Up @@ -80,15 +79,6 @@ class DataChannel extends EventTarget {
*/
accept({ tab, emailProtectionUserData, fireButton }) {
if (tab) {
if (tab.locale) {
// @ts-ignore
if (Object.keys(i18n.options.resources).includes(tab.locale)) {
i18n.changeLanguage(tab.locale)
} else {
console.warn(`Unsupported locale ${tab.locale}`)
}
}

this.tab = tab
this.domain = tab.domain
const MAJOR_TRACKER_THRESHOLD_PCT = 25
Expand Down Expand Up @@ -267,10 +257,6 @@ export function DataProvider({ children }) {
return <ChannelContext.Provider value={{ channel: dc }}>{children}</ChannelContext.Provider>
}

export function useChannel() {
return useContext(ChannelContext).channel
}

/**
* @return {null | DataChannelPublicData}
*/
Expand Down
5 changes: 4 additions & 1 deletion v2/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { h, render } from 'preact'
import { App } from './app'
import { SettingsProvider } from './settings'
import { DataProvider } from './data-provider'
import { TranslationProvider } from './translations'

window.onunhandledrejection = (event) => {
console.warn(`UNHANDLED PROMISE REJECTION: ${event.reason}`)
Expand All @@ -14,7 +15,9 @@ async function init() {
render(
<SettingsProvider>
<DataProvider>
<App />
<TranslationProvider>
<App />
</TranslationProvider>
</DataProvider>
</SettingsProvider>,
app
Expand Down
49 changes: 49 additions & 0 deletions v2/translations.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import { h } from 'preact'
import { createContext } from 'preact'
import { useData } from './data-provider'
import { useEffect, useState } from 'preact/hooks'
import { i18n } from '../shared/js/ui/base/localize'

const TranslationContext = createContext({
/** @type {string} */
locale: 'en',
})

export function TranslationProvider({ children }) {
const data = useData()
const locale = data.tab?.locale
const [ready, setReady] = useState(false)
useEffect(() => {
let cont = new AbortController()
async function fetchFile(locale, signal) {
try {
const s = await fetch(`../locales/${locale}.json`, { signal }).then((x) => x.json())
for (let [ns, translations] of Object.entries(s)) {
i18n.addResourceBundle(locale, ns, translations)
}
} catch (e) {
console.error('could not load locale')
}

if (Object.keys(/** @type {any} */ (i18n.options.resources)).includes(locale)) {
i18n.changeLanguage(locale)
} else {
console.warn(`Unsupported locale ${locale}`)
}
}
if (locale) {
fetchFile(locale, cont.signal)
.then(() => setReady(true))
.catch(console.error)
} else {
console.log('ignoring dup')
}
return () => {
cont.abort()
}
}, [locale])

if (!ready) return null
return <TranslationContext.Provider value={{ locale: 'en' }}>{children}</TranslationContext.Provider>
}

0 comments on commit 224260d

Please sign in to comment.