Skip to content
Merged
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
15 changes: 0 additions & 15 deletions l10n/nl.js
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,6 @@ OC.L10N.register(
"e.g. /Documents/Marketing" : "bijv. /Documenten/Marketing",
"Folder ID (optional, preferred)" : "Map-ID (optioneel, voorkeur)",
"Numeric file id of the folder" : "Numeriek bestand-id van de map",
"View mode" : "Weergave",
"Sort by" : "Sorteer op",
"Sort descending" : "Aflopend sorteren",
"Show thumbnails" : "Miniaturen tonen",
Expand Down Expand Up @@ -990,7 +989,6 @@ OC.L10N.register(
"No widgets match this filter" : "Geen widgets komen overeen met dit filter",
"Catalog" : "Catalogus",
"General" : "Algemeen",
"Group dashboards" : "Groepsdashboards",
"Manage dashboards shared with a Nextcloud group. The “Default group” row controls the org-wide default dashboard set." : "Beheer dashboards die met een Nextcloud-groep worden gedeeld. De rij “Standaardgroep” regelt de organisatiebrede standaard dashboards.",
"Loading groups" : "Groepen laden",
"No groups configured" : "Geen groepen geconfigureerd",
Expand All @@ -1003,26 +1001,18 @@ OC.L10N.register(
"Failed to load group dashboards" : "Laden van groepsdashboards mislukt",
"Failed to delete dashboard" : "Verwijderen van dashboard mislukt",
"Last dashboard cannot be deleted" : "Het laatste dashboard kan niet worden verwijderd",
"Name" : "Naam",
"Icon (Material Design name)" : "Pictogram (Material Design-naam)",
"Layout template" : "Lay-outsjabloon",
"Blank dashboard" : "Leeg dashboard",
"KPI overview" : "KPI-overzicht",
"People & teams" : "Mensen & teams",
"Set as the group default dashboard" : "Instellen als standaard groepsdashboard",
"Cancel" : "Annuleren",
"Create" : "Aanmaken",
"Creating…" : "Bezig met aanmaken…",
"Name must be at least 2 characters" : "Naam moet minstens 2 tekens bevatten",
"Name must be at most 64 characters" : "Naam mag maximaal 64 tekens bevatten",
"Manage dashboards for {group}" : "Dashboards beheren voor {group}",
"Loading dashboards" : "Dashboards laden",
"No dashboards in this group yet" : "Nog geen dashboards in deze groep",
"Default" : "Standaard",
"Set as default" : "Instellen als standaard",
"Rename" : "Hernoemen",
"Delete" : "Verwijderen",
"Close" : "Sluiten",
"New dashboard name" : "Nieuwe dashboardnaam",
"Delete this dashboard? This cannot be undone." : "Dit dashboard verwijderen? Dit kan niet ongedaan worden gemaakt.",
"Maximum dashboards per user" : "Maximum aantal dashboards per gebruiker",
Expand Down Expand Up @@ -1060,7 +1050,6 @@ OC.L10N.register(
"Waiting for content…" : "Wachten op inhoud…",
"Spend analytics" : "Uitgavenanalyse",
"View mode" : "Weergavemodus",
"Period" : "Periode",
"Summary" : "Samenvatting",
"Trend" : "Trend",
"Top vendors" : "Belangrijkste leveranciers",
Expand Down Expand Up @@ -1105,7 +1094,6 @@ OC.L10N.register(
"Acknowledged" : "Bevestigd",
"Pending" : "In afwachting",
"Overdue" : "Te laat",
"User" : "Gebruiker",
"Status" : "Status",
"Acknowledged at" : "Bevestigd op",
"Export CSV" : "CSV exporteren",
Expand Down Expand Up @@ -1400,9 +1388,6 @@ OC.L10N.register(
"Start page without navigation panel" : "Startpagina zonder navigatiepaneel",
"When on, the dashboard view has no left navigation panel and uses the full width. The dashboard switcher and the Documentation, Store, Reports, Features & roadmap and settings destinations are in the Menu button in the top row. Other pages keep the panel." : "Als dit aanstaat heeft de dashboardweergave geen navigatiepaneel links en gebruikt hij de volle breedte. De dashboardkiezer en de bestemmingen Documentatie, Store, Rapporten, Functies en roadmap en instellingen staan dan in de knop Menu in de bovenste rij. Andere pagina's houden het paneel.",
"Personal settings" : "Persoonlijke instellingen",
"Store" : "Store",
"Reports" : "Rapporten",
"Flows" : "Flows",
"Configure your LaunchPad instance with group ordering, demo data, admin roles, and footer settings." : "Configureer je LaunchPad met groepvolgorde, demo-data, beheerdersrollen en voettekstinstellingen.",
"Get your intranet started: configure groups, install demo data, and set up admin roles." : "Start je intranet: configureer groepen, installeer demo-data en stel beheerdersrollen in.",
"A dashboard is shared with you" : "Er wordt een dashboard met je gedeeld",
Expand Down
3 changes: 0 additions & 3 deletions l10n/nl.json
Original file line number Diff line number Diff line change
Expand Up @@ -1377,9 +1377,6 @@
"Start page without navigation panel": "Startpagina zonder navigatiepaneel",
"When on, the dashboard view has no left navigation panel and uses the full width. The dashboard switcher and the Documentation, Store, Reports, Features & roadmap and settings destinations are in the Menu button in the top row. Other pages keep the panel.": "Als dit aanstaat heeft de dashboardweergave geen navigatiepaneel links en gebruikt hij de volle breedte. De dashboardkiezer en de bestemmingen Documentatie, Store, Rapporten, Functies en roadmap en instellingen staan dan in de knop Menu in de bovenste rij. Andere pagina's houden het paneel.",
"Personal settings": "Persoonlijke instellingen",
"Store": "Store",
"Reports": "Rapporten",
"Flows": "Flows",
"Configure your LaunchPad instance with group ordering, demo data, admin roles, and footer settings.": "Configureer je LaunchPad met groepvolgorde, demo-data, beheerdersrollen en voettekstinstellingen.",
"Get your intranet started: configure groups, install demo data, and set up admin roles.": "Start je intranet: configureer groepen, installeer demo-data en stel beheerdersrollen in.",
"A dashboard is shared with you": "Er wordt een dashboard met je gedeeld",
Expand Down
63 changes: 63 additions & 0 deletions src/__tests__/l10nNoDuplicateKeys.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/**
* SPDX-FileCopyrightText: 2026 Conduction B.V. <info@conduction.nl>
* SPDX-License-Identifier: EUPL-1.2
*
* A key appears once in the Dutch catalogues. Parallel pull requests each
* appended the same key; git merged both lines without a conflict, and the
* LAST copy won at runtime. In nl.js that made "Set as default" read
* "Instellen als standaard" and "View mode" read "Weergave", while nl.json
* and the rest of the app said otherwise. JSON.parse and a JS object cannot
* see a duplicate, so this reads the raw text. Approach copied from
* nextcloud-vue tests/l10n/catalogueNoDuplicateKeys.spec.js.
*/
import { readFileSync } from 'fs'
import { join } from 'path'
import { describe, expect, it } from 'vitest'

const DIR = join(__dirname, '../../l10n')

/**
* The keys that occur more than once in one object of a JSON-shaped text.
*
* @param {string} text The raw object text.
* @return {string[]} The duplicated keys.
*/
function duplicateKeys(text) {
const duplicates = []
const seenStack = [new Set()]
const re = /"((?:[^"\\]|\\.)*)"\s*:|[{}]/g
let match
while ((match = re.exec(text)) !== null) {
if (match[0] === '{') {
seenStack.push(new Set())
} else if (match[0] === '}') {
seenStack.pop()
} else {
const seen = seenStack[seenStack.length - 1]
if (seen.has(match[1])) {
duplicates.push(match[1])
}
seen.add(match[1])
}
}
return duplicates
}

describe('Dutch l10n catalogues', () => {
it('nl.json has no key twice', () => {
const text = readFileSync(join(DIR, 'nl.json'), 'utf8')
JSON.parse(text)
expect(duplicateKeys(text)).toEqual([])
})

it('nl.js has no key twice', () => {
const text = readFileSync(join(DIR, 'nl.js'), 'utf8')
// The translations object: from the first "{" to the "}" before the plural rule.
const body = text.slice(text.indexOf('{'), text.lastIndexOf('},'))
expect(duplicateKeys(body)).toEqual([])
})

it('finds a duplicate when there is one', () => {
expect(duplicateKeys('{"a": "1", "b": "2", "a": "3"}')).toEqual(['a'])
})
})
Loading