mirror of
https://gitlab.com/PronounsPage/PronounsPage.git
synced 2025-09-24 05:05:20 -04:00
Merge remote-tracking branch 'origin/main'
This commit is contained in:
commit
8437c47bf7
@ -36,8 +36,11 @@ home:
|
||||
button: 'Zeige den Generator'
|
||||
header2: 'Generiere einen Link'
|
||||
base: 'Ausgehend von'
|
||||
alt: 'Du kannst auch austauschbare Formen in jedes Feld eintragen, z.B. <code>er&sie</code> = „er“ or „sie“.'
|
||||
pronunciation: 'Du kannst auch die Aussprache spezifizieren, die indem du nach einem senkrechten Strich „|“ (mit der Tastenkombination [Alt Gr] und [<>] ) hinzufügst. Benutze dafür die Lautschrift IPA (Internationales Phonetisches Alphabet). Ein Beispiel wäre: <code>sier|siˑʁ</code> = „sier“, ausgesprochen wie /siˑʁ/.'
|
||||
alt: 'Du kannst auch austauschbare Formen in jedes Feld eintragen, z.B. <code>er&sie</code> = „er“ oder „sie“.'
|
||||
pronunciation: >
|
||||
Du kannst auch die Aussprache spezifizieren, die indem du nach einem senkrechten Strich „|“ (mit der Tastenkombination <kbd>Alt Gr+<</kbd>) hinzufügst.
|
||||
Benutze dafür die {https://de.wikipedia.org/wiki/Liste_der_IPA-Zeichen=Lautschrift IPA (Internationales Phonetisches Alphabet)}.
|
||||
Ein Beispiel wäre: <code>sier|zi:ɐ̯</code> = „sier“, ausgesprochen wie /zi:ɐ̯/.
|
||||
whatisit: 'Was ist das Problem mit Pronomen?'
|
||||
mission:
|
||||
header: 'Unsere Mission'
|
||||
@ -246,10 +249,10 @@ faq:
|
||||
Online ist es noch einfacher: Füge einfach deine Pronomen (oder einen Link zu Beispielen von unserer Website) zu deiner „Bio“ hinzu.
|
||||
- >
|
||||
Denke auch daran, dass manche Menschen je nach Situation einen anderen Namen und andere Pronomen verwenden könnten.
|
||||
Sie hatten vielleicht vor manchen Freund*innen oder Arbeitskolleg*innen noch kein Coming Out, aber bei anderen Freund*innen fühlen sie sich wohl und gehen damit offen um.
|
||||
Sie hatten vielleicht vor manchen Freund*innen oder Arbeitskolleg*innen noch kein Coming-out, aber bei anderen Freund*innen fühlen sie sich wohl und gehen damit offen um.
|
||||
Sei rücksichtsvoll. Du kannst zum Beispiel fragen: „Welche Pronomen soll ich vor deiner*m Chef*in benutzen?“, etc.
|
||||
- >
|
||||
Manche Menschen geben mehrere Pronomen an, z.B. „{/er&sie=er/sie}“ oder „{/sier&er=sier/er}“.
|
||||
Manche Menschen geben mehrere Pronomen an, z.B. „{/er&sie=er oder sie}“ oder auch „{/sier&er=sier oder er}“.
|
||||
Das bedeutet, dass sie alle diese Formen mögen. Normalerweise ist die erste die bevorzugte.
|
||||
who-uses-it:
|
||||
question: 'Benutzt das überhaupt irgendwer?'
|
||||
@ -386,7 +389,7 @@ contact:
|
||||
language: >
|
||||
Wir sind ein internationales Team - die Personen, die eine bestimmte Sprachversion erstellt haben, sind
|
||||
möglicherweise nicht dieselben, die deine Nachricht lesen werden. Daher würden wir es begrüßen, wenn du uns in
|
||||
<strong>Englisch or Polnisch</strong> kontaktierst.
|
||||
<strong>Englisch oder Polnisch</strong> kontaktierst.
|
||||
team:
|
||||
name: 'Das „Rat für neutrale Sprache“ Kollektiv'
|
||||
nameShort: 'Kollektiv'
|
||||
@ -569,7 +572,7 @@ profile:
|
||||
names: 'Namen'
|
||||
pronouns: 'Pronomen'
|
||||
pronounsInfo: >
|
||||
Du kannst entweder ein <strong>Pronomen</strong> (z.B. „sier“ or „sie/ihr“) oder einen <strong>Link</strong> (z.B. „https://de.pronouns.page/dey“)
|
||||
Du kannst entweder ein <strong>Pronomen</strong> (z.B. „sier“ oder „sie/ihr“) oder einen <strong>Link</strong> (z.B. „https://de.pronouns.page/dey“)
|
||||
oder <strong>vier benutzerdefinierten Formen</strong> (z.B. „xier/xies/xiem/xien“).
|
||||
Du kannst auch den {/pronomen#generator=<strong>Generator</strong>} verwenden, um die Sätze mit benutzerdefinierten Formen auszufüllen.
|
||||
pronounsNotFound: 'Nicht erkennbares Format. Bitte beachte die oben genannte Anweisung.'
|
||||
@ -673,7 +676,7 @@ profile:
|
||||
relationship: 'Verhältnis (z.B. „Partner*in“, „beste*r Freund*in“)'
|
||||
mutual: 'Diese Verbindung besteht in beide Richtungen'
|
||||
yourMentions:
|
||||
header: 'Mein Umfeld Erwähnungen '
|
||||
header: 'Erwähnungen aus deinem Umfeld'
|
||||
description: >
|
||||
Hier ist die Liste der Personen, die dich zu ihrem Umfeld hinzugefügt haben. Wenn du sie auch zu deinem
|
||||
Umfeld hinzufügst, wird auf beiden Karten ein Häkchen [s:shield-check] angezeigt.
|
||||
@ -739,6 +742,43 @@ profile:
|
||||
success: 'Deine Visitenkarten wurden erfolgreich wiederhergestellt! Die Seite wird nun neugeladen.'
|
||||
error:
|
||||
signature: 'Ungültige Signatur, kann die Integrität der Sicherungsdatei nicht verifizieren'
|
||||
markdown:
|
||||
enable: 'Verwende Formattierung mit Markdown in deiner Visitenkarte'
|
||||
features: 'Zeige unterstützte Markdownsyntax'
|
||||
examples:
|
||||
- 'ein **fettgedruckter** Text'
|
||||
- 'ein _kursiver_ Text'
|
||||
- 'ein `Code`-Fragment'
|
||||
- 'ein ~~durchgestrichener~~ Text'
|
||||
- 'ein ==markierter== Text'
|
||||
- 'ein ^hochgestellter^ Text'
|
||||
- 'ein ~tiefgestellter~ Text'
|
||||
- >
|
||||
benutze einen umgedrehten Schrägstrich `\`, um \_Formatierungszeichen\_ \*\*abzuschalten\*\*,
|
||||
insbesondere bei Gendersternen (wie Autor\*in)
|
||||
calendar:
|
||||
header: 'Kalender'
|
||||
info:
|
||||
- >
|
||||
In diesem Abschnitt kannst du deinen eigenen Kalender erstellen,
|
||||
welcher in deiner Visitenkarte erscheint und den du zu deiner Kalenderapp hinzufügen kannst.
|
||||
- >
|
||||
Wähle aus der Liste von öffentlich gefeierten Ereignissen des Queeren Kalenders
|
||||
oder füge deine eigenen persönlichen Ereignisse hinzu.
|
||||
Beispiele sind Jahrestage des Coming-outs, der Beginn einer HRT, der Tag einer Namensänderung, Jahrestage in deinen Beziehungen etc.
|
||||
customEvents:
|
||||
header: 'Persönliche Ereignisse'
|
||||
disclaimer: 'Dieses Ereignis ist ein persönliches Ereignis, welches von der Person dieser Visitenkarte erstellt wurde'
|
||||
name: 'Ereignisname (z.B. „HRT begonnen“)'
|
||||
month: 'Monat'
|
||||
day: 'Tag'
|
||||
comment: 'Kommentar (optional)'
|
||||
validation:
|
||||
missingName: 'Ereignisname ist erforderlich'
|
||||
missingDate: 'Datum ist erforderlich'
|
||||
invalidDate: 'Datum ist ungültig'
|
||||
publicEvents:
|
||||
header: 'Ereignisse aus dem Queeren Kalender'
|
||||
|
||||
share: 'Teilen'
|
||||
|
||||
@ -1160,6 +1200,8 @@ calendar:
|
||||
list: 'Ereignisliste'
|
||||
link: 'Link'
|
||||
full: 'Ganzer Kalender'
|
||||
onlyFirstDays: 'Version, bei der bei langen Ereignissen nur der jeweils erste Tag eingetragen ist'
|
||||
start: 'Beginn'
|
||||
|
||||
supportBanners:
|
||||
ukraine:
|
||||
|
@ -126,7 +126,7 @@ export default [
|
||||
'footer.source',
|
||||
'error.invalidImage',
|
||||
'profile.banner',
|
||||
'pronoun.example',
|
||||
'profile.example',
|
||||
'calendar.onlyFirstDays',
|
||||
'calendar.start',
|
||||
'calendar.events.nonmonogamy_visibility_day',
|
||||
|
@ -358,11 +358,10 @@ contact:
|
||||
team:
|
||||
name: 'The “Neutral Language Council” collective' # TODO
|
||||
nameShort: 'Collective'
|
||||
description: # TODO
|
||||
- >
|
||||
We are a queer collective dedicated to assembling, researching, shaping and promoting
|
||||
gender neutral and nonbinary language.
|
||||
We also support actions towards equality and social justice.
|
||||
description: > # TODO
|
||||
We are a queer collective dedicated to assembling, researching, shaping and promoting
|
||||
gender neutral and nonbinary language.
|
||||
We also support actions towards equality and social justice.
|
||||
logo: 'Logo of the collective is a combination of the transgender symbol and a speech bubble that symbolises language.' # TODO
|
||||
members: 'Current members' # TODO
|
||||
member: 'Member of the collective' # TODO
|
||||
|
@ -84,7 +84,7 @@ export default ({ app, store }) => {
|
||||
}
|
||||
|
||||
app.router.afterEach(() => {
|
||||
if (typeof window !== 'undefined' && window.fusetag) {
|
||||
if (typeof window !== 'undefined' && window.fusetag && window.fusetag.pageInit) {
|
||||
window.fusetag.pageInit();
|
||||
}
|
||||
});
|
||||
|
@ -19,6 +19,16 @@ export const buildList = (fn, ...args) => {
|
||||
return list;
|
||||
}
|
||||
|
||||
export const deepGet = (obj, path) => {
|
||||
let value = obj;
|
||||
for (let part of path.split('.')) {
|
||||
value = value[part];
|
||||
if (value === undefined) { break; }
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
export const head = ({title, description, banner, noindex = false, keywords}) => {
|
||||
const meta = { meta: [] };
|
||||
|
||||
|
11
src/stats.js
11
src/stats.js
@ -4,19 +4,10 @@ import Plausible from 'plausible-api';
|
||||
import fetch from 'node-fetch';
|
||||
import { ulid } from 'ulid';
|
||||
import expectedTranslations from '../locale/expectedTranslations.js';
|
||||
import { deepGet } from './helpers.js';
|
||||
import fs from 'fs';
|
||||
import Suml from 'suml';
|
||||
|
||||
const deepGet = (obj, path) => {
|
||||
let value = obj;
|
||||
for (let part of path.split('.')) {
|
||||
value = value[part];
|
||||
if (value === undefined) { break; }
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
const formatDate = d => `${d.getFullYear()}-${(d.getMonth() + 1).toString().padStart(2, '0')}-${d.getDate().toString().padStart(2, '0')}`;
|
||||
|
||||
export const buildChart = (rows, cumulative = true) => {
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { deepGet } from './helpers.js';
|
||||
import translations from '../data/translations.suml';
|
||||
import baseTranslations from '../locale/_base/translations.suml';
|
||||
import expectedTranslations from '../locale/expectedTranslations.js';
|
||||
@ -17,17 +18,14 @@ class Translator {
|
||||
}
|
||||
|
||||
get(key, warn = false, base = false, useFallback = true) {
|
||||
let value = base ? this.baseTranslations : this.translations;
|
||||
for (let part of key.split('.')) {
|
||||
value = value[part];
|
||||
if (value === undefined) {
|
||||
if (warn) {
|
||||
console.error('Cannot find translation: ' + key);
|
||||
}
|
||||
if (!base && useFallback) {
|
||||
return this.get(key, warn, true);
|
||||
}
|
||||
return undefined;
|
||||
const translations = base ? this.baseTranslations : this.translations;
|
||||
const value = deepGet(translations, key);
|
||||
if (value === undefined) {
|
||||
if (warn) {
|
||||
console.error('Cannot find translation: ' + key);
|
||||
}
|
||||
if (!base && useFallback) {
|
||||
return this.get(key, warn, true);
|
||||
}
|
||||
}
|
||||
return value;
|
||||
|
69
test/translations.test.js
Normal file
69
test/translations.test.js
Normal file
@ -0,0 +1,69 @@
|
||||
import { expect, test } from '@jest/globals';
|
||||
|
||||
import { loadSumlFromBase } from '../server/loader.js';
|
||||
import { deepGet } from '../src/helpers.js';
|
||||
import expectedTranslations from '../locale/expectedTranslations.js';
|
||||
import locales from '../locale/locales.js';
|
||||
|
||||
const baseTranslations = loadSumlFromBase('locale/_base/translations');
|
||||
const typeFlexibleKeys = new Set(['home.generator.alt']);
|
||||
|
||||
function specificTypeOf(value) {
|
||||
if (typeof(value) === 'object') {
|
||||
if (value === null) {
|
||||
return null;
|
||||
} else if (Array.isArray(value)) {
|
||||
return 'array';
|
||||
} else {
|
||||
return 'object';
|
||||
}
|
||||
} else {
|
||||
return typeof(value);
|
||||
}
|
||||
}
|
||||
|
||||
function toMatchBaseTranslationsSchema(actual) {
|
||||
const messages = recursivelyValidateSchema(actual, baseTranslations);
|
||||
if (messages.length > 0) {
|
||||
return {
|
||||
message: () =>
|
||||
`expected translations to match schema of base translations\n\n${messages.join('\n')}`,
|
||||
pass: false,
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
message: () =>
|
||||
'expected translations to mismatch schema of base translations',
|
||||
pass: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function recursivelyValidateSchema(actual, base, parentKey = '') {
|
||||
const messages = [];
|
||||
for (const [property, value] of Object.entries(actual)) {
|
||||
const key = parentKey ? `${parentKey}.${property}` : property;
|
||||
if (base[property] === undefined || base[property] === null) {
|
||||
continue;
|
||||
}
|
||||
if (value !== null && !typeFlexibleKeys.has(key) && specificTypeOf(value) !== specificTypeOf(base[property])) {
|
||||
messages.push(`${key} has type ${specificTypeOf(value)}, expected ${specificTypeOf(base[property])}`);
|
||||
}
|
||||
if (specificTypeOf(value) === 'object') {
|
||||
messages.push(...recursivelyValidateSchema(value, base[property], key));
|
||||
}
|
||||
}
|
||||
return messages;
|
||||
}
|
||||
|
||||
test.each(locales)('translations of $code match schema of base translations', ({ code }) => {
|
||||
const translations = loadSumlFromBase(`locale/${code}/translations`);
|
||||
expect(translations).toMatchBaseTranslationSchema();
|
||||
});
|
||||
|
||||
test('expected translations are defined in base translations', () => {
|
||||
const undefinedTranslations = expectedTranslations.filter(key => deepGet(baseTranslations, key) === undefined);
|
||||
expect(undefinedTranslations).toEqual([]);
|
||||
});
|
||||
|
||||
expect.extend({ toMatchBaseTranslationSchema: toMatchBaseTranslationsSchema });
|
Loading…
x
Reference in New Issue
Block a user