umami/scripts/translate-3-germanic.cjs
Mike Cao e1ee5eba27
Some checks are pending
Node.js CI / build (push) Waiting to run
Translate all 51 locale files, reducing untranslated keys from 6,017 to 862.
12 batch translation scripts covering all language families: East Asian, Romance,
Germanic, Nordic, Slavic, Other European, South/Southeast Asian, Tamil, Sinhala,
Urdu, and Burmese. Remaining untranslated keys are intentional loanwords (URL, UTM,
SMS, etc.) and en-GB which is intentionally identical to en-US.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 13:04:45 -08:00

326 lines
9.5 KiB
JavaScript

const fs = require('fs');
const path = require('path');
const dir = path.join(__dirname, '..', 'public', 'intl', 'messages');
const enUS = JSON.parse(fs.readFileSync(path.join(dir, 'en-US.json'), 'utf8'));
const translations = {
'de-DE': {
label: {
'account': 'Konto',
'action': 'Aktion',
'add-link': 'Link hinzufügen',
'add-pixel': 'Pixel hinzufügen',
'analysis': 'Analyse',
'application': 'Anwendung',
'audience': 'Zielgruppe',
'boards': 'Boards',
'browser': 'Browser',
'campaign': 'Kampagne',
'channel': 'Kanal',
'chart': 'Diagramm',
'cohorts': 'Kohorten',
'criteria': 'Kriterien',
'desktop': 'Desktop',
'destination-url': 'Ziel-URL',
'details': 'Details',
'documentation': 'Dokumentation',
'domain': 'Domain',
'download': 'Herunterladen',
'email': 'E-Mail',
'environment': 'Umgebung',
'exclude-bounce': 'Absprung ausschließen',
'filter': 'Filter',
'funnels': 'Trichter',
'growth': 'Wachstum',
'hostname': 'Hostname',
'hour': 'Stunde',
'invalid-url': 'Ungültige URL',
'laptop': 'Laptop',
'link': 'Link',
'links': 'Links',
'location': 'Standort',
'max': 'Max',
'medium': 'Medium',
'min': 'Min',
'minute': 'Minute',
'model': 'Modell',
'month': 'Monat',
'name': 'Name',
'number-of-records': '{x} {x, plural, one {Datensatz} other {Datensätze}}',
'ok': 'OK',
'online': 'Online',
'os': 'OS',
'pixel': 'Pixel',
'preferences': 'Einstellungen',
'profiles': 'Profile',
'region': 'Region',
'save-cohort': 'Kohorte speichern',
'save-segment': 'Segment speichern',
'screen': 'Bildschirm',
'segment': 'Segment',
'segments': 'Segmente',
'sms': 'SMS',
'source': 'Quelle',
'support': 'Support',
'switch-account': 'Konto wechseln',
'table': 'Tabelle',
'tablet': 'Tablet',
'tag': 'Tag',
'team': 'Team',
'teams': 'Teams',
'term': 'Suchbegriff',
'traffic': 'Traffic',
'unique-events': 'Einzigartige Ereignisse',
'update': 'Aktualisieren',
'url': 'URL',
'utm': 'UTM',
'utm-campaign': 'UTM-Kampagne',
'utm-content': 'UTM-Inhalt',
'utm-medium': 'UTM-Medium',
'utm-source': 'UTM-Quelle',
'utm-term': 'UTM-Begriff',
'version': 'Version',
'website': 'Website',
'websites': 'Websites'
},
message: {
'bad-request': 'Ungültige Anfrage',
'forbidden': 'Verboten',
'not-found': 'Nicht gefunden',
'nothing-selected': 'Nichts ausgewählt.',
'sever-error': 'Serverfehler',
'unauthorized': 'Nicht autorisiert'
}
},
'de-CH': {
label: {
'account': 'Konto',
'action': 'Aktion',
'add-link': 'Link hinzufügen',
'add-pixel': 'Pixel hinzufügen',
'analysis': 'Analyse',
'application': 'Anwendung',
'audience': 'Zielgruppe',
'boards': 'Boards',
'browser': 'Browser',
'campaign': 'Kampagne',
'channel': 'Kanal',
'chart': 'Diagramm',
'cohorts': 'Kohorten',
'criteria': 'Kriterien',
'desktop': 'Desktop',
'destination-url': 'Ziel-URL',
'details': 'Details',
'documentation': 'Dokumentation',
'domain': 'Domain',
'download': 'Herunterladen',
'email': 'E-Mail',
'environment': 'Umgebung',
'exclude-bounce': 'Absprung ausschliessen',
'filter': 'Filter',
'filters': 'Filter',
'funnels': 'Trichter',
'growth': 'Wachstum',
'hour': 'Stunde',
'invalid-url': 'Ungültige URL',
'laptop': 'Laptop',
'link': 'Link',
'links': 'Links',
'location': 'Standort',
'manager': 'Verwalter',
'max': 'Max',
'medium': 'Medium',
'min': 'Min',
'minute': 'Minute',
'model': 'Modell',
'month': 'Monat',
'name': 'Name',
'number-of-records': '{x} {x, plural, one {Datensatz} other {Datensätze}}',
'ok': 'OK',
'online': 'Online',
'os': 'OS',
'pixel': 'Pixel',
'preferences': 'Einstellungen',
'profiles': 'Profile',
'region': 'Region',
'retention': 'Retention',
'save-cohort': 'Kohorte speichern',
'save-segment': 'Segment speichern',
'screen': 'Bildschirm',
'segment': 'Segment',
'segments': 'Segmente',
'sms': 'SMS',
'source': 'Quelle',
'support': 'Support',
'switch-account': 'Konto wechseln',
'table': 'Tabelle',
'tablet': 'Tablet',
'tag': 'Tag',
'team': 'Team',
'team-id': 'Team-ID',
'teams': 'Teams',
'term': 'Suchbegriff',
'total': 'Total',
'traffic': 'Traffic',
'unique-events': 'Einzigartige Ereignisse',
'update': 'Aktualisieren',
'url': 'URL',
'utm': 'UTM',
'utm-campaign': 'UTM-Kampagne',
'utm-content': 'UTM-Inhalt',
'utm-medium': 'UTM-Medium',
'utm-source': 'UTM-Quelle',
'utm-term': 'UTM-Begriff',
'version': 'Version',
'website': 'Website'
},
message: {
'bad-request': 'Ungültige Anfrage',
'forbidden': 'Verboten',
'not-found': 'Nicht gefunden',
'nothing-selected': 'Nichts ausgewählt.',
'sever-error': 'Serverfehler',
'unauthorized': 'Nicht autorisiert'
}
},
'nl-NL': {
label: {
'account': 'Account',
'action': 'Actie',
'add-link': 'Link toevoegen',
'add-pixel': 'Pixel toevoegen',
'analysis': 'Analyse',
'application': 'Applicatie',
'audience': 'Publiek',
'browser': 'Browser',
'browsers': 'Browsers',
'campaign': 'Campagne',
'channel': 'Kanaal',
'chart': 'Grafiek',
'cohort': 'Cohort',
'cohorts': 'Cohorten',
'criteria': 'Criteria',
'destination-url': 'Bestemmings-URL',
'direct': 'Direct',
'documentation': 'Documentatie',
'download': 'Downloaden',
'email': 'E-mail',
'end-step': 'Eindstap',
'environment': 'Omgeving',
'exclude-bounce': 'Bounce uitsluiten',
'filter': 'Filter',
'filters': 'Filters',
'first-seen': 'Eerst gezien',
'funnel': 'Trechter',
'growth': 'Groei',
'hour': 'Uur',
'invalid-url': 'Ongeldige URL',
'is': 'Is',
'laptop': 'Laptop',
'link': 'Link',
'location': 'Locatie',
'manager': 'Beheerder',
'max': 'Max',
'medium': 'Medium',
'min': 'Min',
'minute': 'Minuut',
'model': 'Model',
'month': 'Maand',
'number-of-records': '{x} {x, plural, one {record} other {records}}',
'ok': 'OK',
'online': 'Online',
'os': 'OS',
'pixel': 'Pixel',
'pixels': 'Pixels',
'preferences': 'Voorkeuren',
'profiles': 'Profielen',
'query': 'Query',
'referrer': 'Verwijzer',
'save-cohort': 'Cohort opslaan',
'save-segment': 'Segment opslaan',
'screen': 'Scherm',
'segment': 'Segment',
'segments': 'Segmenten',
'sms': 'SMS',
'source': 'Bron',
'support': 'Ondersteuning',
'switch-account': 'Wissel van account',
'table': 'Tabel',
'tablet': 'Tablet',
'team': 'Team',
'team-id': 'Team-ID',
'team-websites': 'Teamwebsites',
'teams': 'Teams',
'term': 'Zoekterm',
'traffic': 'Verkeer',
'transactions': 'Transacties',
'transfer': 'Overdragen',
'transfer-website': 'Website overdragen',
'type': 'Type',
'unique': 'Uniek',
'unique-events': 'Unieke gebeurtenissen',
'uniqueCustomers': 'Unieke klanten',
'update': 'Bijwerken',
'url': 'URL',
'utm': 'UTM',
'utm-campaign': 'UTM-campagne',
'utm-content': 'UTM-inhoud',
'utm-description': 'Volg je campagnes via UTM-parameters.',
'utm-medium': 'UTM-medium',
'utm-source': 'UTM-bron',
'utm-term': 'UTM-term',
'version': 'Versie',
'views-per-visit': 'Weergaven per bezoek',
'visits': 'Bezoeken',
'website': 'Website',
'website-id': 'Website-ID',
'websites': 'Websites',
'window': 'Venster'
},
message: {
'bad-request': 'Ongeldig verzoek',
'collected-data': 'Verzamelde gegevens',
'forbidden': 'Verboden',
'not-found': 'Niet gevonden',
'nothing-selected': 'Niets geselecteerd.',
'sever-error': 'Serverfout',
'unauthorized': 'Niet geautoriseerd'
}
},
'en-GB': {
label: {
'behavior': 'Behaviour',
'favorite': 'Favourite',
'color': 'Colour'
},
message: {}
}
};
for (const [locale, trans] of Object.entries(translations)) {
const filePath = path.join(dir, locale + '.json');
const data = JSON.parse(fs.readFileSync(filePath, 'utf8'));
let count = 0;
for (const [section, keys] of Object.entries(trans)) {
for (const [key, value] of Object.entries(keys)) {
if (data[section] && key in data[section]) {
data[section][key] = value;
count++;
}
}
}
const sorted = {};
for (const section of Object.keys(enUS)) {
if (data[section]) {
sorted[section] = {};
for (const key of Object.keys(enUS[section])) {
if (key in data[section]) sorted[section][key] = data[section][key];
}
for (const key of Object.keys(data[section])) {
if (!(key in sorted[section])) sorted[section][key] = data[section][key];
}
}
}
fs.writeFileSync(filePath, JSON.stringify(sorted, null, 2) + '\n', 'utf8');
console.log('Updated ' + locale + ': ' + count + ' keys');
}