feat(bisaya-course): enhance German course content and localization support
All checks were successful
Deploy to production / deploy (push) Successful in 2m47s
All checks were successful
Deploy to production / deploy (push) Successful in 2m47s
- Updated the create-german-for-bisaya-course-content.js script to improve lesson pattern retrieval by introducing a new function for generating a lesson pattern pool. - Added new exercises for various topics including 'Wohnung & Nachbarn', 'Besuch empfangen', 'Arzt, Apotheke, Termin', and 'Amt, Dokumente, Anmeldung', enhancing practical language skills for learners. - Improved localization by integrating translation keys for various UI elements and error messages across multiple components, ensuring a consistent user experience in both German and Bisaya. - Enhanced the main.js file to recognize Bisaya language preferences in browser settings, improving accessibility for users.
This commit is contained in:
@@ -29,13 +29,6 @@ const GERMAN_DIDACTICS = {
|
||||
...GERMAN_FOR_BISAYA_PHASE5_DIDACTICS
|
||||
};
|
||||
|
||||
const GENERIC_DISTRACTOR_PATTERNS = Array.from(new Set(
|
||||
Object.values(GERMAN_DIDACTICS)
|
||||
.flatMap((entry) => Array.isArray(entry?.corePatterns) ? entry.corePatterns : [])
|
||||
.map((pattern) => String(pattern || '').trim())
|
||||
.filter(Boolean)
|
||||
)).slice(0, 300);
|
||||
|
||||
function normalizeText(value) {
|
||||
return String(value || '')
|
||||
.trim()
|
||||
@@ -100,6 +93,18 @@ function pickDistractors(pattern, allPatterns, count) {
|
||||
.slice(0, count);
|
||||
}
|
||||
|
||||
function getLessonPatternPool(didactics) {
|
||||
const speakingCues = (Array.isArray(didactics.speakingPrompts) ? didactics.speakingPrompts : [])
|
||||
.flatMap((entry) => [entry?.cue, entry?.prompt])
|
||||
.map((entry) => normalizeText(entry))
|
||||
.filter(Boolean);
|
||||
|
||||
return Array.from(new Set([
|
||||
...didactics.corePatterns,
|
||||
...speakingCues
|
||||
]));
|
||||
}
|
||||
|
||||
function buildChoiceExercise(lesson, didactics, pattern, allPatterns, variant = 0) {
|
||||
const distractors = pickDistractors(pattern, allPatterns, 3);
|
||||
if (distractors.length < 3) return null;
|
||||
@@ -277,7 +282,7 @@ function generateExercisesFromDidactics(lesson) {
|
||||
|
||||
const patternA = corePatterns[0];
|
||||
const patternB = corePatterns[1] || corePatterns[0];
|
||||
const pool = Array.from(new Set([...corePatterns, ...GENERIC_DISTRACTOR_PATTERNS]));
|
||||
const pool = getLessonPatternPool(didactics);
|
||||
|
||||
if (lesson.lessonType === 'conversation') {
|
||||
return [
|
||||
@@ -561,6 +566,595 @@ const GERMAN_EXERCISES = {
|
||||
},
|
||||
explanation: 'Im Perfekt braucht man hier das Hilfsverb "habe".'
|
||||
}
|
||||
],
|
||||
'Wohnung & Nachbarn': [
|
||||
{
|
||||
exerciseTypeId: 2,
|
||||
title: 'Wohnen passend ausdrücken',
|
||||
instruction: 'Wähle die natürlichste Aussage zur Wohnsituation.',
|
||||
questionData: {
|
||||
type: 'multiple_choice',
|
||||
question: 'Du willst sagen, dass du hier wohnst und den Nachbarn kennst. Welche Form passt?',
|
||||
options: ['Ich wohne hier. Das ist mein Nachbar.', 'Ich bin hier wohnen. Das mein Nachbar.', 'Ich wohne dort Nachbar.', 'Hier wohne ich mein Nachbar.']
|
||||
},
|
||||
answerData: {
|
||||
type: 'multiple_choice',
|
||||
correctAnswer: 0
|
||||
},
|
||||
explanation: 'Im Deutschen sind kurze klare Hauptsätze am Anfang am sichersten.'
|
||||
},
|
||||
{
|
||||
exerciseTypeId: 1,
|
||||
title: 'Wohnort ergänzen',
|
||||
instruction: 'Fülle die Lücke im Satz.',
|
||||
questionData: {
|
||||
type: 'gap_fill',
|
||||
text: 'Ich {gap} hier.',
|
||||
gaps: 1
|
||||
},
|
||||
answerData: {
|
||||
type: 'gap_fill',
|
||||
answers: ['wohne']
|
||||
},
|
||||
explanation: 'Das Kernmuster lautet "Ich wohne hier."'
|
||||
},
|
||||
withTypeName('situational_response', {
|
||||
title: 'Nachbarn kurz vorstellen',
|
||||
instruction: 'Antworte mit zwei kurzen Sätzen auf Deutsch.',
|
||||
questionData: {
|
||||
type: 'situational_response',
|
||||
question: 'Jemand fragt dich: "Wo wohnst du? Und wer ist das?"',
|
||||
keywords: ['wohne', 'hier', 'nachbar']
|
||||
},
|
||||
answerData: {
|
||||
modelAnswer: 'Ich wohne hier. Das ist mein Nachbar.',
|
||||
keywords: ['wohne', 'hier', 'nachbar']
|
||||
},
|
||||
explanation: 'Beide Informationen lassen sich mit zwei sehr einfachen Sätzen sauber ausdrücken.'
|
||||
})
|
||||
],
|
||||
'Besuch empfangen': [
|
||||
{
|
||||
exerciseTypeId: 2,
|
||||
title: 'Gast freundlich begrüßen',
|
||||
instruction: 'Wähle die passende deutsche Reaktion.',
|
||||
questionData: {
|
||||
type: 'multiple_choice',
|
||||
question: 'Ein Gast steht an der Tür. Welche Formulierung passt am besten?',
|
||||
options: ['Komm doch rein. Setz dich bitte.', 'Du kommst rein sitzen bitte.', 'Ich rein bitte du.', 'Setz doch komm rein.']
|
||||
},
|
||||
answerData: {
|
||||
type: 'multiple_choice',
|
||||
correctAnswer: 0
|
||||
},
|
||||
explanation: '"Komm doch rein. Setz dich bitte." klingt freundlich und natürlich.'
|
||||
},
|
||||
{
|
||||
exerciseTypeId: 3,
|
||||
title: 'Einladung richtig bauen',
|
||||
instruction: 'Ordne die Wörter zu einer höflichen Einladung.',
|
||||
questionData: {
|
||||
type: 'sentence_building',
|
||||
question: 'Baue eine freundliche Aufforderung für einen Gast.',
|
||||
tokens: ['Setz', 'dich', 'bitte']
|
||||
},
|
||||
answerData: {
|
||||
correct: ['Setz dich bitte']
|
||||
},
|
||||
explanation: 'Kurze Aufforderungen sind im Alltag sehr häufig.'
|
||||
},
|
||||
withTypeName('speaking_from_memory', {
|
||||
title: 'Begrüßung frei sprechen',
|
||||
instruction: 'Sprich eine kurze Begrüßung für einen Gast frei nach.',
|
||||
questionData: {
|
||||
type: 'speaking_from_memory',
|
||||
question: 'Ein Freund besucht dich. Was sagst du an der Tür?',
|
||||
expectedText: 'Komm doch rein. Setz dich bitte.',
|
||||
keywords: ['komm', 'rein', 'setz', 'bitte']
|
||||
},
|
||||
answerData: {
|
||||
type: 'speaking_from_memory'
|
||||
},
|
||||
explanation: 'Die Übung trainiert einen natürlichen Mini-Dialog beim Empfang von Besuch.'
|
||||
})
|
||||
],
|
||||
'Arzt, Apotheke, Termin': [
|
||||
{
|
||||
exerciseTypeId: 2,
|
||||
title: 'Arzttermin richtig sagen',
|
||||
instruction: 'Wähle die passende Aussage.',
|
||||
questionData: {
|
||||
type: 'multiple_choice',
|
||||
question: 'Du bist beim Arzt und brauchst Medikamente. Welche Form passt?',
|
||||
options: ['Ich habe einen Termin. Ich brauche Medikamente.', 'Ich bin ein Termin. Ich brauche Medizin machen.', 'Ich habe Medikamente Termin.', 'Termin ich brauche.']
|
||||
},
|
||||
answerData: {
|
||||
type: 'multiple_choice',
|
||||
correctAnswer: 0
|
||||
},
|
||||
explanation: 'Beide Aussagen sind typische frühe Standardsätze für Arzt und Apotheke.'
|
||||
},
|
||||
{
|
||||
exerciseTypeId: 1,
|
||||
title: 'Apotheke ergänzen',
|
||||
instruction: 'Setze das passende Wort ein.',
|
||||
questionData: {
|
||||
type: 'gap_fill',
|
||||
text: 'Wo ist die {gap}?',
|
||||
gaps: 1
|
||||
},
|
||||
answerData: {
|
||||
type: 'gap_fill',
|
||||
answers: ['Apotheke']
|
||||
},
|
||||
explanation: 'Das ist eine zentrale Frage für Alltag und Gesundheit.'
|
||||
},
|
||||
withTypeName('situational_response', {
|
||||
title: 'Beim Arzt knapp reagieren',
|
||||
instruction: 'Antworte kurz und passend auf Deutsch.',
|
||||
questionData: {
|
||||
type: 'situational_response',
|
||||
question: 'Die Sprechstundenhilfe fragt: "Haben Sie einen Termin?"',
|
||||
keywords: ['habe', 'termin']
|
||||
},
|
||||
answerData: {
|
||||
modelAnswer: 'Ja, ich habe einen Termin.',
|
||||
keywords: ['habe', 'termin']
|
||||
},
|
||||
explanation: 'Kurze sichere Antworten helfen besonders in belastenden Situationen.'
|
||||
})
|
||||
],
|
||||
'Amt, Dokumente, Anmeldung': [
|
||||
{
|
||||
exerciseTypeId: 2,
|
||||
title: 'Anmeldung im Amt',
|
||||
instruction: 'Wähle die passende deutsche Formulierung.',
|
||||
questionData: {
|
||||
type: 'multiple_choice',
|
||||
question: 'Du willst dich anmelden. Welche Aussage passt?',
|
||||
options: ['Ich möchte mich anmelden.', 'Ich will Anmeldung machen mich.', 'Ich melde ich.', 'Anmelden ich möchte Formular.']
|
||||
},
|
||||
answerData: {
|
||||
type: 'multiple_choice',
|
||||
correctAnswer: 0
|
||||
},
|
||||
explanation: '"Ich möchte mich anmelden." ist ein zentraler Standardsatz für Ämter.'
|
||||
},
|
||||
{
|
||||
exerciseTypeId: 1,
|
||||
title: 'Dokument zeigen',
|
||||
instruction: 'Fülle die Lücke mit dem passenden Wort.',
|
||||
questionData: {
|
||||
type: 'gap_fill',
|
||||
text: 'Hier ist mein {gap}.',
|
||||
gaps: 1
|
||||
},
|
||||
answerData: {
|
||||
type: 'gap_fill',
|
||||
answers: ['Formular']
|
||||
},
|
||||
explanation: 'Das Formular ist ein zentrales Schlüsselwort dieser Lektion.'
|
||||
},
|
||||
{
|
||||
exerciseTypeId: 3,
|
||||
title: 'Adressfrage bauen',
|
||||
instruction: 'Ordne die Wörter zu einer typischen Amtsfrage.',
|
||||
questionData: {
|
||||
type: 'sentence_building',
|
||||
question: 'Baue die Frage nach der Adresse.',
|
||||
tokens: ['Was', 'ist', 'Ihre', 'Adresse']
|
||||
},
|
||||
answerData: {
|
||||
correct: ['Was ist Ihre Adresse']
|
||||
},
|
||||
explanation: 'Solche festen Fragen tauchen in Formular- und Anmeldungssituationen ständig auf.'
|
||||
}
|
||||
],
|
||||
'Nebensätze mit weil - Einstieg': [
|
||||
{
|
||||
exerciseTypeId: 2,
|
||||
title: 'Weil-Satz erkennen',
|
||||
instruction: 'Wähle den grammatisch passenden Satz.',
|
||||
questionData: {
|
||||
type: 'multiple_choice',
|
||||
question: 'Welche Form mit "weil" ist richtig?',
|
||||
options: ['Ich bleibe zu Hause, weil ich krank bin.', 'Ich bleibe zu Hause, weil ich bin krank.', 'Weil ich krank, ich bleibe zu Hause.', 'Ich bleibe weil zu Hause ich krank bin.']
|
||||
},
|
||||
answerData: {
|
||||
type: 'multiple_choice',
|
||||
correctAnswer: 0
|
||||
},
|
||||
explanation: 'Im Nebensatz mit "weil" steht das Verb am Ende.'
|
||||
},
|
||||
{
|
||||
exerciseTypeId: 1,
|
||||
title: 'Weil ergänzen',
|
||||
instruction: 'Setze das passende Bindewort ein.',
|
||||
questionData: {
|
||||
type: 'gap_fill',
|
||||
text: 'Ich komme später, {gap} ich arbeite.',
|
||||
gaps: 1
|
||||
},
|
||||
answerData: {
|
||||
type: 'gap_fill',
|
||||
answers: ['weil']
|
||||
},
|
||||
explanation: 'Mit "weil" gibst du im Deutschen einen Grund an.'
|
||||
},
|
||||
{
|
||||
exerciseTypeId: 3,
|
||||
title: 'Grund richtig ordnen',
|
||||
instruction: 'Ordne die Wörter zu einem korrekten weil-Satz.',
|
||||
questionData: {
|
||||
type: 'sentence_building',
|
||||
question: 'Baue den Grundsatz richtig.',
|
||||
tokens: ['weil', 'ich', 'arbeite']
|
||||
},
|
||||
answerData: {
|
||||
correct: ['weil ich arbeite']
|
||||
},
|
||||
explanation: 'Kleine korrekte Nebensätze sind ein wichtiger nächster Schritt.'
|
||||
}
|
||||
],
|
||||
'Arbeitssuche & Termine': [
|
||||
{
|
||||
exerciseTypeId: 2,
|
||||
title: 'Arbeit suchen',
|
||||
instruction: 'Wähle die passende Aussage.',
|
||||
questionData: {
|
||||
type: 'multiple_choice',
|
||||
question: 'Welche Formulierung passt zu Arbeitssuche und Termin?',
|
||||
options: ['Ich suche Arbeit. Ich habe morgen einen Termin.', 'Ich suche arbeiten. Morgen Termin ich.', 'Ich bin Arbeit suchen.', 'Morgen ich suche Termin Arbeit.']
|
||||
},
|
||||
answerData: {
|
||||
type: 'multiple_choice',
|
||||
correctAnswer: 0
|
||||
},
|
||||
explanation: 'Beide Sätze sind typische kurze Aussagen für Bewerbung und Alltag.'
|
||||
},
|
||||
{
|
||||
exerciseTypeId: 1,
|
||||
title: 'Termin ergänzen',
|
||||
instruction: 'Fülle die Lücke aus.',
|
||||
questionData: {
|
||||
type: 'gap_fill',
|
||||
text: 'Ich habe morgen einen {gap}.',
|
||||
gaps: 1
|
||||
},
|
||||
answerData: {
|
||||
type: 'gap_fill',
|
||||
answers: ['Termin']
|
||||
},
|
||||
explanation: 'Der Termin gehört zu den wichtigsten Alltagswörtern im Deutschen.'
|
||||
}
|
||||
],
|
||||
'Trennbare Verben - Einstieg': [
|
||||
{
|
||||
exerciseTypeId: 2,
|
||||
title: 'Trennbares Verb erkennen',
|
||||
instruction: 'Wähle den richtigen Hauptsatz.',
|
||||
questionData: {
|
||||
type: 'multiple_choice',
|
||||
question: 'Welche Form mit trennbarem Verb ist richtig?',
|
||||
options: ['Ich rufe dich an.', 'Ich anrufe dich.', 'Ich dich rufe an.', 'Ich rufe an dich.']
|
||||
},
|
||||
answerData: {
|
||||
type: 'multiple_choice',
|
||||
correctAnswer: 0
|
||||
},
|
||||
explanation: 'Im Hauptsatz trennt sich das Verb: "Ich rufe dich an."'
|
||||
},
|
||||
{
|
||||
exerciseTypeId: 1,
|
||||
title: 'Trennteil ergänzen',
|
||||
instruction: 'Setze den fehlenden Verbteil ein.',
|
||||
questionData: {
|
||||
type: 'gap_fill',
|
||||
text: 'Ich stehe um sechs Uhr {gap}.',
|
||||
gaps: 1
|
||||
},
|
||||
answerData: {
|
||||
type: 'gap_fill',
|
||||
answers: ['auf']
|
||||
},
|
||||
explanation: 'Bei "aufstehen" steht der Teil "auf" im Hauptsatz am Ende.'
|
||||
}
|
||||
],
|
||||
'Einladungen & soziale Treffen': [
|
||||
{
|
||||
exerciseTypeId: 2,
|
||||
title: 'Einladung formulieren',
|
||||
instruction: 'Wähle die natürlichste Einladung.',
|
||||
questionData: {
|
||||
type: 'multiple_choice',
|
||||
question: 'Du willst jemanden für morgen einladen. Welche Form passt?',
|
||||
options: ['Hast du Zeit? Kommst du morgen?', 'Du Zeit morgen kommst?', 'Morgen du kommst Zeit?', 'Kommst du Zeit hat morgen?']
|
||||
},
|
||||
answerData: {
|
||||
type: 'multiple_choice',
|
||||
correctAnswer: 0
|
||||
},
|
||||
explanation: 'Kurze direkte Fragen sind im Deutschen in dieser Situation sehr üblich.'
|
||||
},
|
||||
withTypeName('situational_response', {
|
||||
title: 'Treffen ausmachen',
|
||||
instruction: 'Antworte kurz und passend auf Deutsch.',
|
||||
questionData: {
|
||||
type: 'situational_response',
|
||||
question: 'Du willst ein Treffen für morgen bestätigen.',
|
||||
keywords: ['morgen', 'zeit']
|
||||
},
|
||||
answerData: {
|
||||
modelAnswer: 'Ja, morgen habe ich Zeit.',
|
||||
keywords: ['morgen', 'zeit']
|
||||
},
|
||||
explanation: 'Die Antwort bestätigt knapp und klar die Verfügbarkeit.'
|
||||
})
|
||||
],
|
||||
'Einkauf, Reklamation, Rückgabe': [
|
||||
{
|
||||
exerciseTypeId: 2,
|
||||
title: 'Rückgabe im Laden',
|
||||
instruction: 'Wähle die passende Reklamation.',
|
||||
questionData: {
|
||||
type: 'multiple_choice',
|
||||
question: 'Ein gekaufter Gegenstand ist kaputt. Was sagst du?',
|
||||
options: ['Das ist kaputt. Ich möchte das zurückgeben.', 'Das kaputt ich zurückgeben.', 'Ich kaputt zurück das.', 'Zurückgeben ich kaputt das.']
|
||||
},
|
||||
answerData: {
|
||||
type: 'multiple_choice',
|
||||
correctAnswer: 0
|
||||
},
|
||||
explanation: 'Das ist die klare und höfliche Standardsituation bei einer Reklamation.'
|
||||
},
|
||||
{
|
||||
exerciseTypeId: 1,
|
||||
title: 'Kassenbon ergänzen',
|
||||
instruction: 'Fülle die Lücke mit dem passenden Wort.',
|
||||
questionData: {
|
||||
type: 'gap_fill',
|
||||
text: 'Haben Sie einen {gap}?',
|
||||
gaps: 1
|
||||
},
|
||||
answerData: {
|
||||
type: 'gap_fill',
|
||||
answers: ['Kassenbon']
|
||||
},
|
||||
explanation: 'Der Kassenbon ist im Rückgabe-Dialog ein sehr typisches Schlüsselwort.'
|
||||
}
|
||||
],
|
||||
'würde / hätte gern - Einstieg': [
|
||||
{
|
||||
exerciseTypeId: 2,
|
||||
title: 'Höflichen Wunsch wählen',
|
||||
instruction: 'Wähle die höflichste Formulierung.',
|
||||
questionData: {
|
||||
type: 'multiple_choice',
|
||||
question: 'Welche Form klingt in einem Servicegespräch höflich?',
|
||||
options: ['Ich hätte gern einen Termin.', 'Ich will Termin.', 'Ich nehme Termin.', 'Termin ich gern habe.']
|
||||
},
|
||||
answerData: {
|
||||
type: 'multiple_choice',
|
||||
correctAnswer: 0
|
||||
},
|
||||
explanation: '"Ich hätte gern ..." ist ein sehr nützliches höfliches Muster.'
|
||||
},
|
||||
{
|
||||
exerciseTypeId: 1,
|
||||
title: 'Wunschform ergänzen',
|
||||
instruction: 'Setze den passenden Ausdruck ein.',
|
||||
questionData: {
|
||||
type: 'gap_fill',
|
||||
text: 'Ich {gap} gern Hilfe.',
|
||||
gaps: 1
|
||||
},
|
||||
answerData: {
|
||||
type: 'gap_fill',
|
||||
answers: ['hätte']
|
||||
},
|
||||
explanation: 'Mit "hätte gern" formuliert man Wünsche höflicher.'
|
||||
}
|
||||
],
|
||||
'Dialogtag - Alltag': [
|
||||
{
|
||||
exerciseTypeId: 2,
|
||||
title: 'Alltagsschritte verbinden',
|
||||
instruction: 'Wähle die natürlichste kleine Alltagsfolge.',
|
||||
questionData: {
|
||||
type: 'multiple_choice',
|
||||
question: 'Welche Minifolge klingt als Alltagsbericht am besten?',
|
||||
options: ['Heute muss ich arbeiten. Danach gehe ich einkaufen.', 'Heute muss ich arbeiten danach ich einkaufen gehe.', 'Ich heute arbeiten muss danach einkaufen.', 'Danach heute ich muss arbeiten.']
|
||||
},
|
||||
answerData: {
|
||||
type: 'multiple_choice',
|
||||
correctAnswer: 0
|
||||
},
|
||||
explanation: 'Die Lektion trainiert verbundene Alltagsschritte in klaren deutschen Hauptsätzen.'
|
||||
},
|
||||
{
|
||||
exerciseTypeId: 3,
|
||||
title: 'Alltagsfolge bauen',
|
||||
instruction: 'Ordne die Wörter zur ersten Aussage.',
|
||||
questionData: {
|
||||
type: 'sentence_building',
|
||||
question: 'Baue einen typischen Alltagsaussagesatz.',
|
||||
tokens: ['Heute', 'muss', 'ich', 'arbeiten']
|
||||
},
|
||||
answerData: {
|
||||
correct: ['Heute muss ich arbeiten']
|
||||
},
|
||||
explanation: 'So trainierst du gleichzeitig Alltagssprache und Satzstellung.'
|
||||
}
|
||||
],
|
||||
'Fehlertraining - Artikel & Kasus I': [
|
||||
{
|
||||
exerciseTypeId: 2,
|
||||
title: 'Kasusform erkennen',
|
||||
instruction: 'Wähle die richtige Form im Satz.',
|
||||
questionData: {
|
||||
type: 'multiple_choice',
|
||||
question: 'Welche Form ist richtig?',
|
||||
options: ['Ich brauche den Termin.', 'Ich brauche dem Termin.', 'Ich brauche der Termin.', 'Ich brauche das Termin.']
|
||||
},
|
||||
answerData: {
|
||||
type: 'multiple_choice',
|
||||
correctAnswer: 0
|
||||
},
|
||||
explanation: 'Bei "brauchen" steht das Objekt hier im Akkusativ: "den Termin".'
|
||||
},
|
||||
{
|
||||
exerciseTypeId: 2,
|
||||
title: 'Präposition mit Dativ',
|
||||
instruction: 'Wähle die korrekte Form mit Präposition.',
|
||||
questionData: {
|
||||
type: 'multiple_choice',
|
||||
question: 'Welche Form ist richtig?',
|
||||
options: ['Ich fahre mit dem Bus.', 'Ich fahre mit den Bus.', 'Ich fahre mit der Bus.', 'Ich fahre mit das Bus.']
|
||||
},
|
||||
answerData: {
|
||||
type: 'multiple_choice',
|
||||
correctAnswer: 0
|
||||
},
|
||||
explanation: 'Nach "mit" steht hier der Dativ: "mit dem Bus".'
|
||||
}
|
||||
],
|
||||
'Rollenspiel - Missverständnisse lösen': [
|
||||
{
|
||||
exerciseTypeId: 2,
|
||||
title: 'Missverständnis klären',
|
||||
instruction: 'Wähle die passendste Reaktion.',
|
||||
questionData: {
|
||||
type: 'multiple_choice',
|
||||
question: 'Du hast etwas nicht verstanden. Was sagst du höflich?',
|
||||
options: ['Ich verstehe das nicht. Können Sie das bitte wiederholen?', 'Ich nicht verstehe. Sie wiederholen.', 'Nicht verstehen ich das.', 'Wiederholen das bitte ich.']
|
||||
},
|
||||
answerData: {
|
||||
type: 'multiple_choice',
|
||||
correctAnswer: 0
|
||||
},
|
||||
explanation: 'Die Kombination aus Klärung und höflicher Bitte ist hier besonders nützlich.'
|
||||
},
|
||||
withTypeName('situational_response', {
|
||||
title: 'Ruhig nachfragen',
|
||||
instruction: 'Antworte mit einer höflichen Nachfrage.',
|
||||
questionData: {
|
||||
type: 'situational_response',
|
||||
question: 'Du hast etwas akustisch nicht verstanden.',
|
||||
keywords: ['verstehe', 'bitte', 'wiederholen']
|
||||
},
|
||||
answerData: {
|
||||
modelAnswer: 'Ich verstehe das nicht. Können Sie das bitte wiederholen?',
|
||||
keywords: ['verstehe', 'bitte', 'wiederholen']
|
||||
},
|
||||
explanation: 'Das Muster lässt sich in vielen realen Situationen direkt verwenden.'
|
||||
})
|
||||
],
|
||||
'Freies Sprechen - Alltag ohne Stütze': [
|
||||
withTypeName('speaking_from_memory', {
|
||||
title: 'Typischen Tag frei erzählen',
|
||||
instruction: 'Sprich frei über einen normalen Tag.',
|
||||
questionData: {
|
||||
type: 'speaking_from_memory',
|
||||
question: 'Erzähle frei: Was machst du zuerst, dann und später?',
|
||||
expectedText: 'Zuerst arbeite ich. Dann gehe ich einkaufen. Später bin ich zu Hause.',
|
||||
keywords: ['zuerst', 'dann', 'später', 'arbeite', 'zu']
|
||||
},
|
||||
answerData: {
|
||||
type: 'speaking_from_memory'
|
||||
},
|
||||
explanation: 'Die Übung trainiert freien Ablauf statt einzelner isolierter Sätze.'
|
||||
}),
|
||||
withTypeName('situational_response', {
|
||||
title: 'Freier Tagesbericht',
|
||||
instruction: 'Antworte mit einem kurzen freien Mini-Bericht.',
|
||||
questionData: {
|
||||
type: 'situational_response',
|
||||
question: 'Was machst du heute und später?',
|
||||
keywords: ['heute', 'dann', 'später']
|
||||
},
|
||||
answerData: {
|
||||
modelAnswer: 'Heute arbeite ich. Dann gehe ich einkaufen. Später bin ich zu Hause.',
|
||||
keywords: ['heute', 'dann', 'später']
|
||||
},
|
||||
explanation: 'Wichtig ist eine klare kleine Struktur, nicht maximale Länge.'
|
||||
})
|
||||
],
|
||||
'Abschlussprüfung - Gesamtpfad': [
|
||||
{
|
||||
exerciseTypeId: 2,
|
||||
title: 'Gesamtpfad - Alltagssituation',
|
||||
instruction: 'Wähle die komplett passendste Reaktion.',
|
||||
questionData: {
|
||||
type: 'multiple_choice',
|
||||
question: 'Du bist neu in Deutschland, hast morgen einen Termin und brauchst heute Hilfe. Welche Aussage passt am besten?',
|
||||
options: ['Ich brauche heute Hilfe. Morgen habe ich einen Termin.', 'Heute Hilfe ich brauche morgen Termin habe.', 'Ich morgen Hilfe heute Termin.', 'Termin morgen Hilfe heute ich.']
|
||||
},
|
||||
answerData: {
|
||||
type: 'multiple_choice',
|
||||
correctAnswer: 0
|
||||
},
|
||||
explanation: 'Die Abschlussprüfung bündelt kurze, funktionale Alltagssprache über mehrere Themen.'
|
||||
},
|
||||
{
|
||||
exerciseTypeId: 1,
|
||||
title: 'Abschluss - wichtiges Kernwort',
|
||||
instruction: 'Fülle das wichtige Alltagswort ein.',
|
||||
questionData: {
|
||||
type: 'gap_fill',
|
||||
text: 'Können Sie mir bitte {gap}?',
|
||||
gaps: 1
|
||||
},
|
||||
answerData: {
|
||||
type: 'gap_fill',
|
||||
answers: ['helfen']
|
||||
},
|
||||
explanation: '"Können Sie mir bitte helfen?" ist ein sehr nützliches Kernmuster für den Gesamtpfad.'
|
||||
},
|
||||
withTypeName('speaking_from_memory', {
|
||||
title: 'Abschluss - frei reagieren',
|
||||
instruction: 'Sprich eine kurze funktionale Antwort frei nach.',
|
||||
questionData: {
|
||||
type: 'speaking_from_memory',
|
||||
question: 'Stell dich vor und nenne ein aktuelles Alltagsproblem.',
|
||||
expectedText: 'Hallo, ich heiße Ana. Ich brauche Hilfe, weil ich morgen einen Termin habe.',
|
||||
keywords: ['hallo', 'heiße', 'hilfe', 'weil', 'termin']
|
||||
},
|
||||
answerData: {
|
||||
type: 'speaking_from_memory'
|
||||
},
|
||||
explanation: 'Die Abschlussübung verbindet Vorstellung, Bedarf und Begründung in einem kurzen freien Beitrag.'
|
||||
})
|
||||
],
|
||||
'Kulturelle Orientierung in Deutschland vertieft': [
|
||||
{
|
||||
exerciseTypeId: 2,
|
||||
title: 'Kulturelle Alltagserwartung',
|
||||
instruction: 'Wähle die Aussage, die gut zum kulturellen Fokus passt.',
|
||||
questionData: {
|
||||
type: 'multiple_choice',
|
||||
question: 'Welche Aussage passt besonders gut zum kulturellen Schwerpunkt dieser Lektion?',
|
||||
options: ['Termine und Pünktlichkeit sind oft sehr wichtig.', 'In Deutschland sind Termine meistens egal.', 'Direktheit ist immer unhöflich.', 'Siezen spielt keine Rolle.']
|
||||
},
|
||||
answerData: {
|
||||
type: 'multiple_choice',
|
||||
correctAnswer: 0
|
||||
},
|
||||
explanation: 'Pünktlichkeit und klare Absprachen sind in vielen Alltagssituationen zentral.'
|
||||
},
|
||||
withTypeName('situational_response', {
|
||||
title: 'Kulturell angemessen reagieren',
|
||||
instruction: 'Antworte mit einer kurzen kulturell passenden Aussage.',
|
||||
questionData: {
|
||||
type: 'situational_response',
|
||||
question: 'Warum ist es wichtig, bei einem Termin pünktlich zu sein?',
|
||||
keywords: ['termin', 'pünktlich', 'wichtig']
|
||||
},
|
||||
answerData: {
|
||||
modelAnswer: 'Termine und Pünktlichkeit sind in Deutschland oft sehr wichtig.',
|
||||
keywords: ['termin', 'pünktlich', 'wichtig']
|
||||
},
|
||||
explanation: 'Die Übung verbindet Sprache mit kultureller Orientierung.'
|
||||
})
|
||||
]
|
||||
};
|
||||
|
||||
|
||||
520
docs/BISAYA_SITE_LOCALIZATION_IMPLEMENTATION_SPEC.md
Normal file
520
docs/BISAYA_SITE_LOCALIZATION_IMPLEMENTATION_SPEC.md
Normal file
@@ -0,0 +1,520 @@
|
||||
# Bisaya-Lokalisierung der Gesamtwebseite: Umsetzungsdokument
|
||||
|
||||
## 1. Ziel
|
||||
|
||||
Die gesamte Webseite soll zusätzlich in `Bisaya` verfügbar werden, nicht nur einzelne Sprachkurse.
|
||||
|
||||
Das Ziel ist:
|
||||
|
||||
- die komplette Produktoberfläche für Bisaya-Nutzer verständlich zu machen
|
||||
- Hauptnavigation, Formulare, Dialoge, Fehlermeldungen und Lernbereiche konsistent zu übersetzen
|
||||
- vorhandene i18n-Struktur weiterzuverwenden statt einen Sonderpfad zu bauen
|
||||
- die Qualität der Übersetzungen hoch zu halten, besonders bei Alltagssprache und sprachdidaktischen Inhalten
|
||||
|
||||
Das ist kein reines JSON-Kopieren. Es ist eine Kombination aus:
|
||||
|
||||
- technischer i18n-Erweiterung
|
||||
- Audit von hartcodierten Strings
|
||||
- kontrollierter Übersetzungsarbeit
|
||||
- fachlicher QA
|
||||
|
||||
## 2. Ist-Stand
|
||||
|
||||
Die aktuelle Lokalisierung ist in [frontend/src/i18n/index.js](/mnt/share/torsten/Programs/YourPart3/frontend/src/i18n/index.js) zentral verdrahtet.
|
||||
|
||||
Derzeit existieren drei Web-Locales:
|
||||
|
||||
- `de`
|
||||
- `en`
|
||||
- `es`
|
||||
|
||||
Die Struktur ist modulartig aufgebaut:
|
||||
|
||||
- `general.json`
|
||||
- `header.json`
|
||||
- `navigation.json`
|
||||
- `home.json`
|
||||
- `chat.json`
|
||||
- `settings.json`
|
||||
- `socialnetwork.json`
|
||||
- `falukant.json`
|
||||
- weitere Funktionsbereiche
|
||||
|
||||
Die bestehende Struktur ist grundsätzlich gut genug für eine vierte Sprache.
|
||||
|
||||
Der Haken ist:
|
||||
|
||||
- es gibt weiterhin viele hartcodierte Texte in Vue-Komponenten
|
||||
- manche Bereiche nutzen bereits sauber `$t(...)`
|
||||
- andere mischen i18n und direkte Strings
|
||||
- einige `tr:`-Muster umgehen die normale Komponentensprache
|
||||
|
||||
Für Bisaya reicht es deshalb nicht, nur neue Locale-Dateien zu erzeugen.
|
||||
|
||||
## 3. Sprachentscheidung
|
||||
|
||||
### 3.1 Locale-Code
|
||||
|
||||
Empfehlung:
|
||||
|
||||
- Web-Locale-Code: `ceb`
|
||||
|
||||
Begründung:
|
||||
|
||||
- `ceb` ist der etablierte technische Code für Cebuano/Bisaya
|
||||
- besser anschlussfähig an Standards und spätere Integrationen
|
||||
- klarer als ein frei erfundener Key wie `bis`
|
||||
|
||||
### 3.2 Sichtbarer Sprachname
|
||||
|
||||
Empfehlung im UI:
|
||||
|
||||
- `Bisaya`
|
||||
|
||||
Optional im Admin-/Technik-Kontext:
|
||||
|
||||
- `Bisaya (Cebuano)`
|
||||
|
||||
### 3.3 Sprachstil
|
||||
|
||||
Der Stil darf nicht zu formal oder zu schulbuchartig sein.
|
||||
|
||||
Empfohlen:
|
||||
|
||||
- alltagsnah
|
||||
- warm
|
||||
- direkt verständlich
|
||||
- kurze Sätze
|
||||
- neutrale, breit verständliche Bisaya-Formulierungen
|
||||
|
||||
Nicht empfohlen:
|
||||
|
||||
- künstlich hochsprachliche Formulierungen
|
||||
- unnötig spanisch geprägte oder regionale Spezialformen, wenn einfachere Alternativen reichen
|
||||
- gemischtes Englisch-Bisaya ohne klare Regel
|
||||
|
||||
## 4. Produktentscheidung
|
||||
|
||||
Die Bisaya-Lokalisierung wird als vollwertige vierte Oberfläche behandelt, nicht als Teil des Sprachkurs-Features.
|
||||
|
||||
Das heißt:
|
||||
|
||||
- Bisaya ist globale UI-Sprache
|
||||
- dieselbe Sprache kann zusätzlich als Lernsprache in Kursen vorkommen
|
||||
- Website-Locale und Sprachkursinhalt sind fachlich getrennt
|
||||
|
||||
Wichtig:
|
||||
|
||||
- `Website-Bisaya` ist Produkt-Lokalisierung
|
||||
- `Bisaya-Sprachkurs` ist Lerninhalt
|
||||
|
||||
Das muss technisch und redaktionell getrennt bleiben.
|
||||
|
||||
## 5. Hauptprobleme, die vor der Übersetzung geklärt werden müssen
|
||||
|
||||
### 5.1 Hartcodierte Strings
|
||||
|
||||
Die größte technische Altlast sind direkte Texte in Komponenten.
|
||||
|
||||
Beispiele aus dem aktuellen Frontend:
|
||||
|
||||
- Abschnittslabels in Komponenten wie [AppSectionBar.vue](/mnt/share/torsten/Programs/YourPart3/frontend/src/components/AppSectionBar.vue)
|
||||
- direkte Buttontexte und Statusmeldungen in Views
|
||||
- Fehlermeldungen, die als deutscher Klartext im Code stehen
|
||||
- teils auch Titel, Platzhalter und Hilfetexte
|
||||
|
||||
Konsequenz:
|
||||
|
||||
- vor oder während der Bisaya-Einführung müssen diese Texte systematisch in i18n überführt werden
|
||||
|
||||
### 5.2 Fallback-Logik
|
||||
|
||||
Aktuell ist `fallbackLocale: 'de'` gesetzt.
|
||||
|
||||
Für Bisaya ist das kurzfristig okay, aber fachlich nicht ideal.
|
||||
|
||||
Empfehlung:
|
||||
|
||||
- während der Einführung: globaler Fallback kann vorerst `de` bleiben
|
||||
- mittelfristig: für `ceb` bevorzugt auf `en` oder spezifisches Ketten-Fallback umstellen
|
||||
|
||||
Zielbild:
|
||||
|
||||
```js
|
||||
fallbackLocale: {
|
||||
ceb: ['en', 'de'],
|
||||
default: ['de']
|
||||
}
|
||||
```
|
||||
|
||||
So landet ein Bisaya-Nutzer bei fehlenden Schlüsseln nicht sofort in Deutsch.
|
||||
|
||||
### 5.3 Übersetzungstiefe
|
||||
|
||||
Nicht alles muss in einem Schritt übersetzt werden.
|
||||
|
||||
Wir brauchen klare Ebenen:
|
||||
|
||||
- Shell und Navigation zuerst
|
||||
- Hauptnutzungspfade danach
|
||||
- Spezialbereiche später
|
||||
|
||||
## 6. Übersetzungsprinzipien
|
||||
|
||||
### 6.1 Quelle
|
||||
|
||||
Primäre Übersetzungsquelle sollte `de` sein.
|
||||
|
||||
Begründung:
|
||||
|
||||
- das Produkt wird aktuell stark deutsch geführt
|
||||
- viele Texte sind fachlich auf Deutsch zuerst gepflegt
|
||||
- so vermeiden wir doppelte Drift zwischen `de` und `en`
|
||||
|
||||
### 6.2 Glossar
|
||||
|
||||
Vor dem Massenübersetzen braucht es ein verbindliches Glossar.
|
||||
|
||||
Pflichtbegriffe:
|
||||
|
||||
- Anmeldung
|
||||
- Einstellungen
|
||||
- Freunde
|
||||
- Nachrichten
|
||||
- Chat
|
||||
- Kurs
|
||||
- Lektion
|
||||
- Übung
|
||||
- Wiederholung
|
||||
- Abschluss
|
||||
- Senden
|
||||
- Löschen
|
||||
- Speichern
|
||||
- Suche
|
||||
- Zurück
|
||||
- Weiter
|
||||
|
||||
Zusätzlich fachliche Glossare für:
|
||||
|
||||
- Vokabeltrainer
|
||||
- Falukant
|
||||
- Socialnetwork
|
||||
- Moderation
|
||||
- Erotik-Bereich
|
||||
|
||||
### 6.3 Nicht alles wörtlich
|
||||
|
||||
Die beste Bisaya-UI ist nicht immer die wörtlichste.
|
||||
|
||||
Beispiel:
|
||||
|
||||
- kurze, handlungsnahe Buttons sind wichtiger als exakte 1:1-Übertragung
|
||||
- Hilfetexte dürfen freier formuliert werden, solange der Zweck gleich bleibt
|
||||
|
||||
### 6.4 Konsistenzregeln
|
||||
|
||||
Es muss pro Begriff genau eine Standardform geben, außer es gibt einen klaren Kontextgrund.
|
||||
|
||||
Beispiel:
|
||||
|
||||
- `Weiter` nicht an einer Stelle frei übersetzen und an anderer nur halb Englisch lassen
|
||||
- `Lektion` und `Kurs` nicht ständig unterschiedlich umschreiben
|
||||
|
||||
## 7. Rollout-Phasen
|
||||
|
||||
## 7.1 Phase A: Technische Basis
|
||||
|
||||
Ziel:
|
||||
|
||||
- `ceb` als viertes Locale technisch einführen
|
||||
|
||||
Umfang:
|
||||
|
||||
- neue Locale-Dateien unter `frontend/src/i18n/locales/ceb/`
|
||||
- Ergänzung in [index.js](/mnt/share/torsten/Programs/YourPart3/frontend/src/i18n/index.js)
|
||||
- Sprachumschalter auf `ceb` erweitern
|
||||
- Store- und Default-Sprachlogik prüfen
|
||||
|
||||
Ergebnis:
|
||||
|
||||
- die App kann Bisaya als UI-Sprache laden
|
||||
- zunächst mit vielen Fallbacks, aber technisch sauber
|
||||
|
||||
## 7.2 Phase B: Shell und globale Oberfläche
|
||||
|
||||
Ziel:
|
||||
|
||||
- die Seite fühlt sich sofort als Bisaya-Oberfläche an
|
||||
|
||||
Umfang:
|
||||
|
||||
- `general.json`
|
||||
- `header.json`
|
||||
- `navigation.json`
|
||||
- `message.json`
|
||||
- `error.json`
|
||||
|
||||
Zusätzlich:
|
||||
|
||||
- hartcodierte Hauptnavigationen in Komponenten in i18n überführen
|
||||
|
||||
Ergebnis:
|
||||
|
||||
- Header, Footer, Navigation, Standarddialoge, Basisaktionen und Fehlermeldungen sind in Bisaya
|
||||
|
||||
## 7.3 Phase C: Einstiegspfade
|
||||
|
||||
Ziel:
|
||||
|
||||
- zentrale Nutzungspfade vollständig lokalisieren
|
||||
|
||||
Umfang:
|
||||
|
||||
- `home.json`
|
||||
- `register.json`
|
||||
- `activate.json`
|
||||
- `passwordReset.json`
|
||||
- `settings.json`
|
||||
- allgemeine No-Login-/Login-Flows
|
||||
|
||||
Ergebnis:
|
||||
|
||||
- neue Nutzer können die Plattform in Bisaya betreten und bedienen
|
||||
|
||||
## 7.4 Phase D: Socialnetwork und Sprachlernen
|
||||
|
||||
Ziel:
|
||||
|
||||
- Hauptanwendungsbereich für Community und Lernen abdecken
|
||||
|
||||
Umfang:
|
||||
|
||||
- `socialnetwork.json`
|
||||
- `friends.json`
|
||||
- Vokabeltrainer-Views
|
||||
- Sprachkurs-Views
|
||||
- Such- und Dialogflächen im Social-Bereich
|
||||
|
||||
Wichtig:
|
||||
|
||||
- Sprachlerntexte im Kurs selbst nicht blind mitsynchronisieren
|
||||
- UI-Texte ja, Lerninhalte separat prüfen
|
||||
|
||||
## 7.5 Phase E: Falukant und Spezialbereiche
|
||||
|
||||
Ziel:
|
||||
|
||||
- komplexe Produktmodule sauber nachziehen
|
||||
|
||||
Umfang:
|
||||
|
||||
- `falukant.json`
|
||||
- `blog.json`
|
||||
- `chat.json`
|
||||
- `minigames.json`
|
||||
- Admin-Bereiche optional später
|
||||
|
||||
Hinweis:
|
||||
|
||||
- Falukant ist textlich sehr groß und fachlich komplex
|
||||
- dafür braucht es gesonderte QA
|
||||
|
||||
## 8. Technische Umsetzung
|
||||
|
||||
### 8.1 Neue Locale-Dateien
|
||||
|
||||
Geplante Struktur:
|
||||
|
||||
```text
|
||||
frontend/src/i18n/locales/ceb/
|
||||
activate.json
|
||||
admin.json
|
||||
blog.json
|
||||
chat.json
|
||||
error.json
|
||||
falukant.json
|
||||
friends.json
|
||||
general.json
|
||||
header.json
|
||||
home.json
|
||||
message.json
|
||||
minigames.json
|
||||
navigation.json
|
||||
passwordReset.json
|
||||
personal.json
|
||||
register.json
|
||||
settings.json
|
||||
socialnetwork.json
|
||||
```
|
||||
|
||||
### 8.2 Import in i18n
|
||||
|
||||
In [frontend/src/i18n/index.js](/mnt/share/torsten/Programs/YourPart3/frontend/src/i18n/index.js):
|
||||
|
||||
- alle `ceb`-Dateien importieren
|
||||
- vierten `messages.ceb`-Block ergänzen
|
||||
- Fallback-Regel ggf. modernisieren
|
||||
|
||||
### 8.3 Sprachwahl im Store
|
||||
|
||||
In [frontend/src/store/index.js](/mnt/share/torsten/Programs/YourPart3/frontend/src/store/index.js):
|
||||
|
||||
- `setLanguage` muss `ceb` akzeptieren
|
||||
- Browser-Spracherkennung bleibt vorerst `de/en`, außer wir wollen `ceb` aktiv auch automatisch setzen
|
||||
|
||||
Empfehlung:
|
||||
|
||||
- Auto-Default nicht auf `ceb`
|
||||
- Bisaya bewusst auswählbar machen
|
||||
|
||||
### 8.4 UI-Auswahl erweitern
|
||||
|
||||
Komponenten wie:
|
||||
|
||||
- [SettingsWidget.vue](/mnt/share/torsten/Programs/YourPart3/frontend/src/components/SettingsWidget.vue)
|
||||
|
||||
müssen `ceb` als auswählbare Sprache bekommen.
|
||||
|
||||
## 9. Audit von Nicht-i18n-Texten
|
||||
|
||||
Vor der Vollübersetzung braucht es einen String-Audit.
|
||||
|
||||
Kategorien:
|
||||
|
||||
1. komplett hartcodierte Texte
|
||||
2. gemischte Texte mit Teil-i18n
|
||||
3. technische Fehlermeldungen
|
||||
4. Admin-/Debugtexte, die bewusst vorerst unübersetzt bleiben dürfen
|
||||
|
||||
Besonders kritisch:
|
||||
|
||||
- [AppSectionBar.vue](/mnt/share/torsten/Programs/YourPart3/frontend/src/components/AppSectionBar.vue)
|
||||
- Views mit hero-texten und Buttons
|
||||
- direkte Dialogtitel
|
||||
- direkte Success-/Error-Meldungen in JS-Dateien
|
||||
|
||||
Empfehlung:
|
||||
|
||||
- zuerst Audit-Backlog erzeugen
|
||||
- dann Bereich für Bereich in i18n ziehen
|
||||
|
||||
## 10. Übersetzungsworkflow
|
||||
|
||||
### 10.1 Empfohlener Ablauf pro Datei
|
||||
|
||||
1. deutsche Quelldatei nehmen
|
||||
2. Schlüsselstruktur unverändert lassen
|
||||
3. Bisaya-Datei anlegen
|
||||
4. problematische Begriffe mit Glossar abgleichen
|
||||
5. UI-Stichprobe im echten Produkt machen
|
||||
|
||||
### 10.2 Qualitätssicherung
|
||||
|
||||
Jede größere Datei braucht:
|
||||
|
||||
- formale Prüfung: alle Keys vorhanden
|
||||
- Produktprüfung: Text passt im Layout
|
||||
- Sprachprüfung: natürliches Bisaya
|
||||
- Kontextprüfung: Button- und Fehlermeldungstexte klingen im UI sinnvoll
|
||||
|
||||
### 10.3 Platzhalter und Variablen
|
||||
|
||||
Besondere Aufmerksamkeit für:
|
||||
|
||||
- `{count}`
|
||||
- `{minutes}`
|
||||
- `{title}`
|
||||
- `{name}`
|
||||
- plural-/choice-nahe Muster
|
||||
|
||||
Bisaya-Übersetzungen müssen Variablen und Platzhalter exakt beibehalten.
|
||||
|
||||
## 11. Inhaltliche Risiken
|
||||
|
||||
### 11.1 Falukant
|
||||
|
||||
Falukant hat viele produktinterne Begriffe.
|
||||
|
||||
Risiko:
|
||||
|
||||
- zu direkte Übersetzung zerstört die interne Fachsprache
|
||||
|
||||
Empfehlung:
|
||||
|
||||
- einige Begriffe bewusst nicht übersetzen
|
||||
- stattdessen mit konsistenten Lehnformen arbeiten
|
||||
|
||||
### 11.2 Sprachkurs-Bereich
|
||||
|
||||
Risiko:
|
||||
|
||||
- UI wird lokalisiert, Lerninhalt aber versehentlich mitübersetzt, obwohl er als Kursmaterial bestehen bleiben soll
|
||||
|
||||
Empfehlung:
|
||||
|
||||
- klare Trennung zwischen:
|
||||
- UI-Text
|
||||
- Kursinhalt
|
||||
- Vokabel-/Satzmaterial
|
||||
|
||||
### 11.3 Mischnutzung Deutsch/Bisaya
|
||||
|
||||
Viele Nutzer könnten Deutsch lernen und gleichzeitig die Website in Bisaya benutzen.
|
||||
|
||||
Das ist erlaubt, aber nur wenn:
|
||||
|
||||
- UI-Lokalisierung stabil ist
|
||||
- Kursinhalt nicht durcheinandergerät
|
||||
|
||||
## 12. Priorisierte Umsetzung
|
||||
|
||||
Empfohlene Reihenfolge:
|
||||
|
||||
1. `ceb` technisch einführen
|
||||
2. Sprachumschalter erweitern
|
||||
3. `general/header/navigation/message/error`
|
||||
4. hartcodierte Shell-Texte bereinigen
|
||||
5. `settings/home/register/passwordReset`
|
||||
6. `socialnetwork/friends`
|
||||
7. Vokabeltrainer- und Kurs-UI
|
||||
8. Chat/Blog/Minigames
|
||||
9. Falukant
|
||||
10. Admin-Bereich optional zuletzt
|
||||
|
||||
## 13. Definition von "fertig"
|
||||
|
||||
Die Bisaya-Weblokalisierung ist erst dann wirklich fertig, wenn:
|
||||
|
||||
- `ceb` als Sprache global auswählbar ist
|
||||
- Hauptnavigation und Standardsystemtexte lokalisiert sind
|
||||
- zentrale Nutzerflüsse ohne Deutsch funktionieren
|
||||
- Sprachkurs-UI sauber lokalisiert ist
|
||||
- Falukant und Spezialmodule zumindest konsistent oder bewusst ausgeklammert sind
|
||||
- fehlende Keys systematisch kontrolliert werden
|
||||
|
||||
## 14. Konkrete nächste technische Phase
|
||||
|
||||
Die sinnvolle erste echte Bauphase ist:
|
||||
|
||||
### Phase 1
|
||||
|
||||
- `frontend/src/i18n/locales/ceb/` anlegen
|
||||
- `index.js` für `ceb` erweitern
|
||||
- `SettingsWidget.vue` Sprachwahl erweitern
|
||||
- `AppSectionBar.vue` und vergleichbare Shell-Komponenten in i18n ziehen
|
||||
- `general/header/navigation/message/error` auf Bisaya anlegen
|
||||
|
||||
Erst danach lohnt es sich, größere Produktbereiche wie Socialnetwork oder Falukant vollständig zu übersetzen.
|
||||
|
||||
## 15. Ergebnis
|
||||
|
||||
Die Website in Bisaya zu lokalisieren ist machbar und passt gut zur bestehenden Struktur, aber nur, wenn wir es als echtes Produktprojekt behandeln.
|
||||
|
||||
Die richtige Reihenfolge ist:
|
||||
|
||||
- erst technische Sprachbasis
|
||||
- dann Shell und Kernpfade
|
||||
- dann die großen Module
|
||||
- parallel dazu Audit und Bereinigung harter Strings
|
||||
|
||||
So entsteht keine halbfertige vierte Sprache, sondern eine wirklich benutzbare Bisaya-Oberfläche.
|
||||
@@ -10,76 +10,76 @@
|
||||
class="app-section-bar__back"
|
||||
@click="navigateBack"
|
||||
>
|
||||
Zurück
|
||||
{{ $t('general.general.back') }}
|
||||
</button>
|
||||
</section>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
const SECTION_LABELS = [
|
||||
{ test: (path) => path.startsWith('/falukant'), label: 'Falukant' },
|
||||
{ test: (path) => path.startsWith('/socialnetwork/vocab'), label: 'Vokabeltrainer' },
|
||||
{ test: (path) => path.startsWith('/socialnetwork/forum'), label: 'Forum' },
|
||||
{ test: (path) => path.startsWith('/socialnetwork'), label: 'Community' },
|
||||
{ test: (path) => path.startsWith('/friends'), label: 'Community' },
|
||||
{ test: (path) => path.startsWith('/settings'), label: 'Einstellungen' },
|
||||
{ test: (path) => path.startsWith('/admin'), label: 'Administration' },
|
||||
{ test: (path) => path.startsWith('/minigames'), label: 'Minispiele' },
|
||||
{ test: (path) => path.startsWith('/personal'), label: 'Persönlich' },
|
||||
{ test: (path) => path.startsWith('/blogs'), label: 'Blog' }
|
||||
{ test: (path) => path.startsWith('/falukant'), labelKey: 'general.sectionBar.sections.falukant' },
|
||||
{ test: (path) => path.startsWith('/socialnetwork/vocab'), labelKey: 'general.sectionBar.sections.vocab' },
|
||||
{ test: (path) => path.startsWith('/socialnetwork/forum'), labelKey: 'general.sectionBar.sections.forum' },
|
||||
{ test: (path) => path.startsWith('/socialnetwork'), labelKey: 'general.sectionBar.sections.community' },
|
||||
{ test: (path) => path.startsWith('/friends'), labelKey: 'general.sectionBar.sections.community' },
|
||||
{ test: (path) => path.startsWith('/settings'), labelKey: 'general.sectionBar.sections.settings' },
|
||||
{ test: (path) => path.startsWith('/admin'), labelKey: 'general.sectionBar.sections.administration' },
|
||||
{ test: (path) => path.startsWith('/minigames'), labelKey: 'general.sectionBar.sections.minigames' },
|
||||
{ test: (path) => path.startsWith('/personal'), labelKey: 'general.sectionBar.sections.personal' },
|
||||
{ test: (path) => path.startsWith('/blogs'), labelKey: 'general.sectionBar.sections.blog' }
|
||||
];
|
||||
|
||||
const TITLE_MAP = {
|
||||
Friends: 'Freunde',
|
||||
Guestbook: 'Gästebuch',
|
||||
'Search users': 'Suche',
|
||||
Gallery: 'Galerie',
|
||||
Forum: 'Forum',
|
||||
ForumTopic: 'Thema',
|
||||
Diary: 'Tagebuch',
|
||||
VocabTrainer: 'Sprachen',
|
||||
VocabNewLanguage: 'Neue Sprache',
|
||||
VocabSubscribe: 'Sprache abonnieren',
|
||||
VocabLanguage: 'Sprache',
|
||||
VocabChapter: 'Kapitel',
|
||||
VocabCourses: 'Kurse',
|
||||
VocabCourse: 'Kurs',
|
||||
VocabLesson: 'Lektion',
|
||||
FalukantCreate: 'Charakter erstellen',
|
||||
FalukantOverview: 'Übersicht',
|
||||
BranchView: 'Niederlassung',
|
||||
MoneyHistoryView: 'Geldverlauf',
|
||||
FalukantFamily: 'Familie',
|
||||
HouseView: 'Haus',
|
||||
NobilityView: 'Adel',
|
||||
ReputationView: 'Ansehen',
|
||||
ChurchView: 'Kirche',
|
||||
EducationView: 'Bildung',
|
||||
BankView: 'Bank',
|
||||
DirectorView: 'Direktoren',
|
||||
HealthView: 'Gesundheit',
|
||||
PoliticsView: 'Politik',
|
||||
UndergroundView: 'Untergrund',
|
||||
'Personal settings': 'Persönliche Daten',
|
||||
'View settings': 'Ansicht',
|
||||
'Sexuality settings': 'Sexualität',
|
||||
'Flirt settings': 'Flirt',
|
||||
'Account settings': 'Account',
|
||||
'Language assistant settings': 'Sprachassistent',
|
||||
Interests: 'Interessen',
|
||||
AdminInterests: 'Interessenverwaltung',
|
||||
AdminUsers: 'Benutzer',
|
||||
AdminUserStatistics: 'Benutzerstatistik',
|
||||
AdminContacts: 'Kontaktanfragen',
|
||||
AdminUserRights: 'Rechte',
|
||||
AdminForums: 'Forumverwaltung',
|
||||
AdminChatRooms: 'Chaträume',
|
||||
AdminFalukantEditUserView: 'Falukant-Nutzer',
|
||||
AdminFalukantMapRegionsView: 'Falukant-Karte',
|
||||
AdminFalukantCreateNPCView: 'NPC erstellen',
|
||||
AdminMinigames: 'Match3-Verwaltung',
|
||||
AdminTaxiTools: 'Taxi-Tools',
|
||||
AdminServicesStatus: 'Service-Status'
|
||||
Friends: 'general.sectionBar.titles.friends',
|
||||
Guestbook: 'general.sectionBar.titles.guestbook',
|
||||
'Search users': 'general.sectionBar.titles.search',
|
||||
Gallery: 'general.sectionBar.titles.gallery',
|
||||
Forum: 'general.sectionBar.titles.forum',
|
||||
ForumTopic: 'general.sectionBar.titles.topic',
|
||||
Diary: 'general.sectionBar.titles.diary',
|
||||
VocabTrainer: 'general.sectionBar.titles.languages',
|
||||
VocabNewLanguage: 'general.sectionBar.titles.newLanguage',
|
||||
VocabSubscribe: 'general.sectionBar.titles.subscribeLanguage',
|
||||
VocabLanguage: 'general.sectionBar.titles.language',
|
||||
VocabChapter: 'general.sectionBar.titles.chapter',
|
||||
VocabCourses: 'general.sectionBar.titles.courses',
|
||||
VocabCourse: 'general.sectionBar.titles.course',
|
||||
VocabLesson: 'general.sectionBar.titles.lesson',
|
||||
FalukantCreate: 'general.sectionBar.titles.createCharacter',
|
||||
FalukantOverview: 'general.sectionBar.titles.overview',
|
||||
BranchView: 'general.sectionBar.titles.branch',
|
||||
MoneyHistoryView: 'general.sectionBar.titles.moneyHistory',
|
||||
FalukantFamily: 'general.sectionBar.titles.family',
|
||||
HouseView: 'general.sectionBar.titles.house',
|
||||
NobilityView: 'general.sectionBar.titles.nobility',
|
||||
ReputationView: 'general.sectionBar.titles.reputation',
|
||||
ChurchView: 'general.sectionBar.titles.church',
|
||||
EducationView: 'general.sectionBar.titles.education',
|
||||
BankView: 'general.sectionBar.titles.bank',
|
||||
DirectorView: 'general.sectionBar.titles.directors',
|
||||
HealthView: 'general.sectionBar.titles.health',
|
||||
PoliticsView: 'general.sectionBar.titles.politics',
|
||||
UndergroundView: 'general.sectionBar.titles.underground',
|
||||
'Personal settings': 'general.sectionBar.titles.personalSettings',
|
||||
'View settings': 'general.sectionBar.titles.viewSettings',
|
||||
'Sexuality settings': 'general.sectionBar.titles.sexualitySettings',
|
||||
'Flirt settings': 'general.sectionBar.titles.flirtSettings',
|
||||
'Account settings': 'general.sectionBar.titles.accountSettings',
|
||||
'Language assistant settings': 'general.sectionBar.titles.languageAssistantSettings',
|
||||
Interests: 'general.sectionBar.titles.interests',
|
||||
AdminInterests: 'general.sectionBar.titles.adminInterests',
|
||||
AdminUsers: 'general.sectionBar.titles.adminUsers',
|
||||
AdminUserStatistics: 'general.sectionBar.titles.adminUserStatistics',
|
||||
AdminContacts: 'general.sectionBar.titles.adminContacts',
|
||||
AdminUserRights: 'general.sectionBar.titles.adminUserRights',
|
||||
AdminForums: 'general.sectionBar.titles.adminForums',
|
||||
AdminChatRooms: 'general.sectionBar.titles.adminChatRooms',
|
||||
AdminFalukantEditUserView: 'general.sectionBar.titles.adminFalukantUsers',
|
||||
AdminFalukantMapRegionsView: 'general.sectionBar.titles.adminFalukantMap',
|
||||
AdminFalukantCreateNPCView: 'general.sectionBar.titles.adminCreateNpc',
|
||||
AdminMinigames: 'general.sectionBar.titles.adminMinigames',
|
||||
AdminTaxiTools: 'general.sectionBar.titles.adminTaxiTools',
|
||||
AdminServicesStatus: 'general.sectionBar.titles.adminServicesStatus'
|
||||
};
|
||||
|
||||
export default {
|
||||
@@ -93,10 +93,11 @@ export default {
|
||||
},
|
||||
sectionLabel() {
|
||||
const found = SECTION_LABELS.find((entry) => entry.test(this.routePath));
|
||||
return found?.label || 'Bereich';
|
||||
return this.$t(found?.labelKey || 'general.sectionBar.sections.default');
|
||||
},
|
||||
pageTitle() {
|
||||
return TITLE_MAP[this.$route?.name] || this.sectionLabel;
|
||||
const titleKey = TITLE_MAP[this.$route?.name];
|
||||
return titleKey ? this.$t(titleKey) : this.sectionLabel;
|
||||
},
|
||||
backTarget() {
|
||||
const params = this.$route?.params || {};
|
||||
|
||||
@@ -173,13 +173,14 @@ export default {
|
||||
this.fetchSettings();
|
||||
} catch (err) {
|
||||
console.error('Error updating setting:', err);
|
||||
showApiError(this, err, 'Änderung konnte nicht gespeichert werden.');
|
||||
showApiError(this, err, 'tr:settings.feedback.updateError');
|
||||
}
|
||||
},
|
||||
languagesList() {
|
||||
return [
|
||||
{ value: 'en', captionTr: 'settings.personal.languages.en' },
|
||||
{ value: 'de', captionTr: 'settings.personal.languages.de' },
|
||||
{ value: 'en', captionTr: 'settings.personal.language.en' },
|
||||
{ value: 'de', captionTr: 'settings.personal.language.de' },
|
||||
{ value: 'ceb', captionTr: 'settings.personal.language.ceb' },
|
||||
];
|
||||
},
|
||||
convertToInt(value) {
|
||||
@@ -207,7 +208,7 @@ export default {
|
||||
});
|
||||
} catch (err) {
|
||||
console.error('Error updating visibility:', err);
|
||||
showApiError(this, err, 'Sichtbarkeit konnte nicht aktualisiert werden.');
|
||||
showApiError(this, err, 'tr:settings.feedback.visibilityUpdateError');
|
||||
}
|
||||
},
|
||||
openContactDialog() {
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
<div class="form-field">
|
||||
<label for="password-reset-email">{{ $t("passwordReset.email") }}</label>
|
||||
<input id="password-reset-email" type="email" v-model="email" required :class="{ 'field-error': emailTouched && !isEmailValid }" />
|
||||
<span class="form-hint">Wir senden den Link an die hinterlegte E-Mail-Adresse.</span>
|
||||
<span v-if="emailTouched && !isEmailValid" class="form-error">Bitte eine gültige E-Mail-Adresse eingeben.</span>
|
||||
<span class="form-hint">{{ $t("passwordReset.emailHint") }}</span>
|
||||
<span v-if="emailTouched && !isEmailValid" class="form-error">{{ $t("passwordReset.validation.invalidEmail") }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</DialogWidget>
|
||||
|
||||
@@ -6,23 +6,23 @@
|
||||
<div class="form-field">
|
||||
<label for="register-email">{{ $t("register.email") }}</label>
|
||||
<input id="register-email" type="email" v-model="email" :class="{ 'field-error': emailTouched && !isEmailValid }" />
|
||||
<span v-if="emailTouched && !isEmailValid" class="form-error">Bitte eine gültige E-Mail-Adresse eingeben.</span>
|
||||
<span v-if="emailTouched && !isEmailValid" class="form-error">{{ $t("register.validation.invalidEmail") }}</span>
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label for="register-username">{{ $t("register.username") }}</label>
|
||||
<input id="register-username" type="text" v-model="username" :class="{ 'field-error': usernameTouched && !isUsernameValid }" />
|
||||
<span v-if="usernameTouched && !isUsernameValid" class="form-error">Der Benutzername sollte mindestens 3 Zeichen haben.</span>
|
||||
<span v-if="usernameTouched && !isUsernameValid" class="form-error">{{ $t("register.validation.usernameTooShort") }}</span>
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label for="register-password">{{ $t("register.password") }}</label>
|
||||
<input id="register-password" type="password" v-model="password" :class="{ 'field-error': passwordTouched && !isPasswordValid }" />
|
||||
<span class="form-hint">Mindestens 8 Zeichen.</span>
|
||||
<span v-if="passwordTouched && !isPasswordValid" class="form-error">Das Passwort ist noch zu kurz.</span>
|
||||
<span class="form-hint">{{ $t("register.validation.passwordHint") }}</span>
|
||||
<span v-if="passwordTouched && !isPasswordValid" class="form-error">{{ $t("register.validation.passwordTooShort") }}</span>
|
||||
</div>
|
||||
<div class="form-field">
|
||||
<label for="register-repeat-password">{{ $t("register.repeatPassword") }}</label>
|
||||
<input id="register-repeat-password" type="password" v-model="repeatPassword" :class="{ 'field-error': repeatPasswordTouched && !doPasswordsMatch }" />
|
||||
<span v-if="repeatPasswordTouched && !doPasswordsMatch" class="form-error">Die Passwörter stimmen nicht überein.</span>
|
||||
<span v-if="repeatPasswordTouched && !doPasswordsMatch" class="form-error">{{ $t("register.passwordMismatch") }}</span>
|
||||
</div>
|
||||
<SelectDropdownWidget labelTr="settings.personal.label.language" :v-model="language"
|
||||
tooltipTr="settings.personal.tooltip.language" :list="languages" :value="language" />
|
||||
@@ -104,7 +104,9 @@ export default {
|
||||
async getBrowserLanguage() {
|
||||
const browserLanguage = navigator.language || navigator.languages[0];
|
||||
let short = '';
|
||||
if (browserLanguage.startsWith('de')) {
|
||||
if (browserLanguage.startsWith('ceb') || browserLanguage.startsWith('bis')) {
|
||||
short = 'ceb';
|
||||
} else if (browserLanguage.startsWith('de')) {
|
||||
short = 'de';
|
||||
} else {
|
||||
short = 'en';
|
||||
|
||||
@@ -19,6 +19,23 @@ import enBlog from './locales/en/blog.json';
|
||||
import enMinigames from './locales/en/minigames.json';
|
||||
import enMessage from './locales/en/message.json';
|
||||
import enPersonal from './locales/en/personal.json';
|
||||
import cebGeneral from './locales/ceb/general.json';
|
||||
import cebHeader from './locales/ceb/header.json';
|
||||
import cebNavigation from './locales/ceb/navigation.json';
|
||||
import cebHome from './locales/ceb/home.json';
|
||||
import cebRegister from './locales/ceb/register.json';
|
||||
import cebActivate from './locales/ceb/activate.json';
|
||||
import cebError from './locales/ceb/error.json';
|
||||
import cebMessage from './locales/ceb/message.json';
|
||||
import cebSettings from './locales/ceb/settings.json';
|
||||
import cebPasswordReset from './locales/ceb/passwordReset.json';
|
||||
import cebSocialNetwork from './locales/ceb/socialnetwork.json';
|
||||
import cebFriends from './locales/ceb/friends.json';
|
||||
import cebChat from './locales/ceb/chat.json';
|
||||
import cebPersonal from './locales/ceb/personal.json';
|
||||
import cebFalukant from './locales/ceb/falukant.json';
|
||||
import cebBlog from './locales/ceb/blog.json';
|
||||
import cebMinigames from './locales/ceb/minigames.json';
|
||||
|
||||
import deGeneral from './locales/de/general.json';
|
||||
import deHeader from './locales/de/header.json';
|
||||
@@ -79,6 +96,43 @@ const messages = {
|
||||
...enMessage,
|
||||
...enPersonal,
|
||||
},
|
||||
ceb: {
|
||||
...enGeneral,
|
||||
...enHeader,
|
||||
...enNavigation,
|
||||
...enHome,
|
||||
...enChat,
|
||||
...enRegister,
|
||||
...enPasswordReset,
|
||||
...enError,
|
||||
...enActivate,
|
||||
...enSettings,
|
||||
...enAdmin,
|
||||
...enSocialNetwork,
|
||||
...enFriends,
|
||||
...enFalukant,
|
||||
...enBlog,
|
||||
...enMinigames,
|
||||
...enMessage,
|
||||
...enPersonal,
|
||||
...cebGeneral,
|
||||
...cebHeader,
|
||||
...cebNavigation,
|
||||
...cebHome,
|
||||
...cebRegister,
|
||||
...cebActivate,
|
||||
...cebError,
|
||||
...cebMessage,
|
||||
...cebSettings,
|
||||
...cebPasswordReset,
|
||||
...cebSocialNetwork,
|
||||
...cebFriends,
|
||||
...cebChat,
|
||||
...cebPersonal,
|
||||
...cebFalukant,
|
||||
...cebBlog,
|
||||
...cebMinigames,
|
||||
},
|
||||
de: {
|
||||
'Ok': 'Ok',
|
||||
...deGeneral,
|
||||
|
||||
9
frontend/src/i18n/locales/ceb/activate.json
Normal file
9
frontend/src/i18n/locales/ceb/activate.json
Normal file
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"activate": {
|
||||
"title": "I-activate ang access",
|
||||
"message": "Kumusta {username}. Palihog isulod ang code nga among gipadala pinaagi sa email.",
|
||||
"token": "Token:",
|
||||
"submit": "Ipadala",
|
||||
"failure": "Wala molampos ang activation."
|
||||
}
|
||||
}
|
||||
61
frontend/src/i18n/locales/ceb/blog.json
Normal file
61
frontend/src/i18n/locales/ceb/blog.json
Normal file
@@ -0,0 +1,61 @@
|
||||
{
|
||||
"blog": {
|
||||
"posts": "Mga post",
|
||||
"noPosts": "Walay mga post.",
|
||||
"newPost": "Pagsulat og bag-ong post",
|
||||
"title": "Pamagat",
|
||||
"publish": "I-publish",
|
||||
"pickImage": "Pilia ang hulagway",
|
||||
"uploadImage": "I-upload ang hulagway",
|
||||
"list": {
|
||||
"eyebrow": "Mga community blog",
|
||||
"title": "Mga blog",
|
||||
"intro": "Mga artikulo, update sa proyekto ug personal nga mga panan-aw gikan sa komunidad sa YourPart.",
|
||||
"create": "Paghimo og bag-ong blog",
|
||||
"loading": "Nag-load…",
|
||||
"empty": "Walay blog nga nakit-an.",
|
||||
"by": "gikan kang",
|
||||
"unknownAuthor": "Wala mailhi",
|
||||
"open": "Ablihi ang blog",
|
||||
"fallbackExcerpt": "Mga public nga entry, hunahuna ug update sa proyekto gikan sa komunidad."
|
||||
},
|
||||
"view": {
|
||||
"loading": "Nag-load…",
|
||||
"edit": "Usba",
|
||||
"entriesCount": "{count} ka entry",
|
||||
"empty": "Walay mga entry.",
|
||||
"fallbackDescription": "Public nga community blog sa YourPart.",
|
||||
"notFoundTitle": "Wala makit-i ang blog | YourPart",
|
||||
"notFoundDescription": "Dili ma-load ang gipangayong blog."
|
||||
},
|
||||
"editor": {
|
||||
"createTitle": "Paghimo og blog",
|
||||
"editTitle": "Usba ang blog",
|
||||
"description": "Deskripsyon",
|
||||
"visibility": "Visibility",
|
||||
"visibilityPublic": "Public",
|
||||
"visibilityLoggedIn": "Mga naka-login nga user lang",
|
||||
"ageRange": "Sakop sa edad",
|
||||
"gender": "Gender",
|
||||
"genderMale": "Lalaki",
|
||||
"genderFemale": "Babaye",
|
||||
"save": "I-save",
|
||||
"newPostTitle": "Bag-ong post",
|
||||
"addPost": "Idugang ang post",
|
||||
"shareTitle": "Ipaambit ang blog",
|
||||
"url": "URL",
|
||||
"copyLink": "Kopyaha ang link",
|
||||
"shareToFriends": "Ipadala sa mga higala",
|
||||
"emailAddresses": "Mga e-mail address (bulag sa comma)",
|
||||
"send": "Ipadala",
|
||||
"restrictedHint": "Pahimangno: dili public kini nga blog. Basin magkinahanglan og login ug hustong edad/gender permissions ang makadawat.",
|
||||
"invalidAgeRange": "Dili balido ang sakop sa edad.",
|
||||
"copySuccess": "Nakopya ang link",
|
||||
"copyError": "Napakyas ang pagkopya",
|
||||
"shareError": "Napakyas ang pagpaambit",
|
||||
"emailError": "Napakyas ang pagpadala sa e-mail",
|
||||
"friendsSent": "Napadala sa {count} ka higala.",
|
||||
"emailsSent": "{count} ka e-mail ang napadala."
|
||||
}
|
||||
}
|
||||
}
|
||||
158
frontend/src/i18n/locales/ceb/chat.json
Normal file
158
frontend/src/i18n/locales/ceb/chat.json
Normal file
@@ -0,0 +1,158 @@
|
||||
{
|
||||
"chat": {
|
||||
"multichat": {
|
||||
"title": "Multi Chat",
|
||||
"eroticTitle": "Erotic chat",
|
||||
"autoscroll": "Auto scroll",
|
||||
"options": "Mga kapilian",
|
||||
"send": "Ipadala",
|
||||
"shout": "Singgit",
|
||||
"action": "Aksyon",
|
||||
"roll": "Roll",
|
||||
"colorpicker": "Pilia ang kolor",
|
||||
"colorpicker_preview": "Preview: kini nga mensahe mogamit sa napiling kolor.",
|
||||
"hex": "HEX",
|
||||
"invalid_hex": "Dili balido nga HEX value",
|
||||
"hue": "Hue",
|
||||
"saturation": "Saturation",
|
||||
"lightness": "Lightness",
|
||||
"ok": "Ok",
|
||||
"cancel": "I-cancel",
|
||||
"placeholder": "Isulat ang mensahe…",
|
||||
"action_select_user": "Palihog pagpili og user",
|
||||
"action_to": "Aksyon ngadto kang {to}",
|
||||
"action_phrases": {
|
||||
"left_room": "mibalhin sa room",
|
||||
"leaves_room": "mibiya sa room",
|
||||
"left_chat": "mibiya na sa chat."
|
||||
},
|
||||
"system": {
|
||||
"room_entered": "Misulod ka sa room nga \"{room}\".",
|
||||
"user_entered_room": "Misulod si {user} sa room.",
|
||||
"user_left_room": "Mibiya si {user} sa room.",
|
||||
"color_changed_self": "Giusab nimo ang imong kolor ngadto sa {color}.",
|
||||
"color_changed_user": "Giusab ni {user} ang iyang kolor ngadto sa {color}."
|
||||
},
|
||||
"status": {
|
||||
"connecting": "Nagkonektar…",
|
||||
"connected": "Nakakonektar",
|
||||
"disconnected": "Naputol ang koneksyon",
|
||||
"error": "Sayop sa koneksyon"
|
||||
},
|
||||
"reloadRooms": "I-reload ang mga room",
|
||||
"createRoom": {
|
||||
"toggleShowChat": "Ipakita ang chat",
|
||||
"toggleCreateRoom": "Paghimo og room",
|
||||
"title": "Paghimo og bag-ong room",
|
||||
"commandPrefix": "Command",
|
||||
"labels": {
|
||||
"roomName": "Ngalan sa room",
|
||||
"visibility": "Visibility",
|
||||
"gender": "Gender",
|
||||
"minAge": "Pinakagamay nga edad",
|
||||
"maxAge": "Pinakadako nga edad",
|
||||
"password": "Password",
|
||||
"rightId": "Gikinahanglang right",
|
||||
"typeId": "Room type",
|
||||
"friendsOnly": "friends_only=true"
|
||||
},
|
||||
"placeholders": {
|
||||
"roomName": "pananglitan Lounge",
|
||||
"password": "walay spaces"
|
||||
},
|
||||
"options": {
|
||||
"none": "(wala)",
|
||||
"visibilityPublic": "Public",
|
||||
"visibilityPrivate": "Private",
|
||||
"genderMale": "Lalaki",
|
||||
"genderFemale": "Babaye",
|
||||
"genderAny": "Bisan kinsa / walay limitasyon"
|
||||
},
|
||||
"actions": {
|
||||
"create": "Paghimo og room",
|
||||
"reset": "I-reset"
|
||||
},
|
||||
"validation": {
|
||||
"roomNameRequired": "Gikinahanglan ang ngalan sa room.",
|
||||
"minAgeInvalid": "Ang min_age kinahanglan >= 0.",
|
||||
"maxAgeInvalid": "Ang max_age kinahanglan >= 0.",
|
||||
"ageRangeInvalid": "Dili puwede nga mas dako ang min_age kaysa max_age.",
|
||||
"passwordSpaces": "Ang password dili puwedeng adunay spaces.",
|
||||
"rightIdInvalid": "Ang right_id kinahanglan > 0.",
|
||||
"typeIdInvalid": "Ang type_id kinahanglan > 0."
|
||||
},
|
||||
"messages": {
|
||||
"noConnection": "Walay koneksyon sa chat server.",
|
||||
"invalidForm": "Palihog ayuha ang mga input sa room form.",
|
||||
"roomNameMissing": "Palihog isulod ang ngalan sa room.",
|
||||
"sent": "Napadala na ang room creation: {command}",
|
||||
"created": "Malampuson nga nahimo ang room nga \"{room}\".",
|
||||
"createNotConfirmed": "Ang room nga \"{room}\" wala pa makumpirma. Palihog susiha ang room list."
|
||||
},
|
||||
"ownedRooms": {
|
||||
"title": "Akong mga nahimong room",
|
||||
"hint": "Tangtanga pinaagi sa daemon command: /dr <roomname> (alias: /delete_room <roomname>)",
|
||||
"empty": "Wala ka pay kaugalingong room.",
|
||||
"public": "public",
|
||||
"private": "private",
|
||||
"confirmDelete": "Tinuod ba nga gusto nimong tangtangon ang room nga \"{room}\"?",
|
||||
"deleteSent": "Napadala na ang delete command: /dr {room}",
|
||||
"deleteError": "Dili matangtang ang room."
|
||||
},
|
||||
"rights": {
|
||||
"mainadmin": "Pangunang administrador",
|
||||
"contactrequests": "Mga request sa kontak",
|
||||
"users": "Mga user",
|
||||
"userrights": "Mga katungod sa user",
|
||||
"forum": "Forum",
|
||||
"interests": "Mga interes",
|
||||
"falukant": "Falukant",
|
||||
"minigames": "Mini games",
|
||||
"match3": "Match3",
|
||||
"taxiTools": "Taxi tools",
|
||||
"chatrooms": "Chat rooms",
|
||||
"servicesStatus": "Status sa serbisyo"
|
||||
},
|
||||
"types": {}
|
||||
},
|
||||
"password": {
|
||||
"title": "Gikinahanglan ang password",
|
||||
"inputLabel": "Isulod ang password",
|
||||
"submit": "Sulod sa room",
|
||||
"cancel": "I-cancel",
|
||||
"requiredPrompt": "Ang room nga \"{room}\" gi-protektahan og password. Palihog isulod ang password:",
|
||||
"invalidPrompt": "Sayop ang password para sa \"{room}\". Palihog sulayi pag-usab:",
|
||||
"cancelled": "Nakansela ang pagsulod sa \"{room}\".",
|
||||
"empty": "Dili puwedeng walay sulod ang password."
|
||||
}
|
||||
},
|
||||
"randomchat": {
|
||||
"title": "Random Chat",
|
||||
"close": "Isira",
|
||||
"age": "Edad",
|
||||
"gender": {
|
||||
"title": "Gender",
|
||||
"female": "Babaye",
|
||||
"male": "Lalaki"
|
||||
},
|
||||
"agerange": "Sakop sa edad",
|
||||
"gendersearch": "Pagpangita sumala sa gender",
|
||||
"camonly": "Cam lang",
|
||||
"showcam": "Ipakita ang cam",
|
||||
"addfriend": "Idugang isip higala",
|
||||
"autosearch": "Auto search",
|
||||
"input": "Input",
|
||||
"start": "Sugdi",
|
||||
"waitingForMatch": "Naghulat og ka-match...",
|
||||
"chatpartner": "Nakig-chat ka karon sa usa ka <gender> nga tawo nga <age> ka tuig ang panuigon.",
|
||||
"partnergenderm": "lalaki",
|
||||
"partnergenderf": "babaye",
|
||||
"self": "Ikaw",
|
||||
"partner": "Kaatbang",
|
||||
"jumptonext": "Tapusa kining chat",
|
||||
"userleftchat": "Mibiya na ang ka-chat sa panag-istorya.",
|
||||
"startsearch": "Pangita sa sunod nga panag-istorya",
|
||||
"selfstopped": "Mibiya ka sa panag-istorya."
|
||||
}
|
||||
}
|
||||
}
|
||||
7
frontend/src/i18n/locales/ceb/error.json
Normal file
7
frontend/src/i18n/locales/ceb/error.json
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"error": {
|
||||
"title": "Adunay nahitabo nga sayop",
|
||||
"close": "Isira",
|
||||
"credentialsinvalid": "Dili husto ang imong login data."
|
||||
}
|
||||
}
|
||||
509
frontend/src/i18n/locales/ceb/falukant.json
Normal file
509
frontend/src/i18n/locales/ceb/falukant.json
Normal file
@@ -0,0 +1,509 @@
|
||||
{
|
||||
"falukant": {
|
||||
"weather": {
|
||||
"sunny": "Adlawon",
|
||||
"cloudy": "Dag-um",
|
||||
"rainy": "Ulanon",
|
||||
"stormy": "Bagyo",
|
||||
"snowy": "Nag-niyebe",
|
||||
"foggy": "Mahaw-ang",
|
||||
"windy": "Mahangin",
|
||||
"clear": "Klaro"
|
||||
},
|
||||
"debtorsPrison": {
|
||||
"actionBlocked": "Kini nga aksyon gi-block samtang naa ka sa debtors' prison.",
|
||||
"globalWarning": "Ang imong kalangan sa utang nagsugod na og limit sa imong mga aksyon. Posible nga mosunod dayon ang pinugos nga mga lakang.",
|
||||
"globalLocked": "Naa ka sa debtors' prison. Hapit tanan aktibong aksyon sa Falukant karon gi-block."
|
||||
},
|
||||
"messages": {
|
||||
"title": "Mga mensahe",
|
||||
"tooltip": "Mga mensahe",
|
||||
"empty": "Walay mga mensahe.",
|
||||
"markAllRead": "Timan-i tanan isip nabasa"
|
||||
},
|
||||
"notifications": {
|
||||
"notify_election_created": "Giskedyul ang usa ka bag-ong eleksiyon.",
|
||||
"director_death": "Namatay si {characterName} sa edad nga {ageYears}. Isip amo, kinahanglan kang magtudlo og bag-ong direktor.{regionLabel}{spouses}{children}{lovers}",
|
||||
"relationship_death": "Namatay si {characterName} sa edad nga {ageYears}.{regionLabel}{spouses}{children}{lovers}",
|
||||
"child_death": "Namatay ang imong anak nga si {characterName} sa edad nga {ageYears}.{regionLabel}",
|
||||
"production": {
|
||||
"overproduction": "Sobra nga produksyon: ang imong produksyon kay {value}% mas taas kaysa panginahanglan."
|
||||
},
|
||||
"transport": {
|
||||
"waiting": "Naghulat ang transport",
|
||||
"modes": {
|
||||
"land": "Yuta",
|
||||
"water": "Tubig",
|
||||
"unknown": "Wala mailhi"
|
||||
},
|
||||
"speed": {
|
||||
"1": "Hinay",
|
||||
"2": "Katamtaman",
|
||||
"3": "Paspas",
|
||||
"4": "Pinakapaspas",
|
||||
"unknown": "Wala mailhi"
|
||||
}
|
||||
},
|
||||
"random_event": {
|
||||
"windfall": {
|
||||
"title": "Kalit nga swerte",
|
||||
"description": "Nakakita ka og nakalimtang pitaka sa dalan. Nadawat nimo ang {amount}."
|
||||
},
|
||||
"theft": {
|
||||
"title": "Kawat",
|
||||
"description": "Adunay kawatan nga nagkuha sa bahin sa imong kuwarta. Kawala: {amount}."
|
||||
},
|
||||
"warehouse_fire": {
|
||||
"title": "Sunog sa bodega",
|
||||
"description": "Ang sunog nakadaot sa bahin sa imong bodega.{damagePercent}{destructionPercent}"
|
||||
},
|
||||
"character_illness": {
|
||||
"title": "Sakit",
|
||||
"description": "Nagsakit si {characterName} ug nawad-an og {healthChange} health."
|
||||
},
|
||||
"character_recovery": {
|
||||
"title": "Pagkamaayo",
|
||||
"description": "Naayo si {characterName} gikan sa sakit ug nabawi ang {healthChange} health."
|
||||
},
|
||||
"character_accident": {
|
||||
"title": "Aksidente",
|
||||
"description": "Ang grabe nga aksidente nakapasakit pag-ayo kang {characterName}. Health: {healthChange}."
|
||||
},
|
||||
"sudden_infant_death": {
|
||||
"title": "Kalit nga pagkamatay sa masuso",
|
||||
"description": "Kalit nga namatay si {characterName}."
|
||||
},
|
||||
"regional_storm": {
|
||||
"title": "Bagyo sa rehiyon",
|
||||
"description": "Grabe nga bagyo ang miigo sa rehiyon nga {regionName}."
|
||||
},
|
||||
"regional_festival": {
|
||||
"title": "Pista sa rehiyon",
|
||||
"description": "Adunay dakong pista sa rehiyon nga {regionName}."
|
||||
},
|
||||
"regional_epidemic": {
|
||||
"title": "Epidemya",
|
||||
"description": "Naigo sa epidemya ang rehiyon nga {regionName}."
|
||||
},
|
||||
"earthquake": {
|
||||
"title": "Linog",
|
||||
"description": "Naigo sa linog ang rehiyon nga {regionName}."
|
||||
}
|
||||
}
|
||||
},
|
||||
"statusbar": {
|
||||
"age": "Edad",
|
||||
"wealth": "Kadato",
|
||||
"health": "Panglawas",
|
||||
"events": "Mga panghitabo",
|
||||
"relationship": "Relasyon",
|
||||
"children": "Mga anak",
|
||||
"children_unbaptised": "Mga anak nga wala pa mabunyagi"
|
||||
},
|
||||
"overview": {
|
||||
"title": "Falukant - Overview",
|
||||
"heroIntro": "Ang imong kahimtang sa ekonomiya, pamilya ug kabtangan sa usa ka mubo ug klarong overview.",
|
||||
"heirSelection": {
|
||||
"title": "Pagpili og manununod",
|
||||
"description": "Dili na magamit ang imong daang karakter. Pagpili og manununod gikan sa lista aron magpadayon sa duwa.",
|
||||
"loading": "Nag-load sa posibleng mga manununod…",
|
||||
"noHeirs": "Walay available nga mga manununod.",
|
||||
"select": "Pilia isip play character",
|
||||
"error": "Sayop sa pagpili sa manununod."
|
||||
},
|
||||
"metadata": {
|
||||
"title": "Personal",
|
||||
"name": "Ngalan",
|
||||
"money": "Kadato",
|
||||
"age": "Edad",
|
||||
"years": "Tuig",
|
||||
"days": "Adlaw",
|
||||
"mainbranch": "Pulong-balay nga siyudad",
|
||||
"nobleTitle": "Titulo",
|
||||
"certificate": "Sertipiko"
|
||||
},
|
||||
"certificate": {
|
||||
"title": "Progreso sa sertipiko",
|
||||
"description": "Nagpakita sa imong karon nga level ug sa mga kinahanglanon para sa sunod nga promotion.",
|
||||
"current": "Karon",
|
||||
"next": "Sunod nga level",
|
||||
"levelMatrix": "Mga produkto per certificate level",
|
||||
"levelLabel": "Level {level}",
|
||||
"score": "Puntos",
|
||||
"ready": "Andam na para sa sunod nga promotion",
|
||||
"notReady": "Wala pa maabot ang mga kinahanglanon",
|
||||
"factors": "Karon nga mga bili",
|
||||
"requirements": "Mga kinahanglanon sa sunod nga level"
|
||||
},
|
||||
"summary": {
|
||||
"certificateHint": "Mao kini ang nagbuot kung unsang mga kategoriya sa produkto ang pwede nimong himuon karon.",
|
||||
"branches": "Mga branch",
|
||||
"branchesHint": "Direktang access sa imong labing importante nga mga lokasyon sa negosyo.",
|
||||
"productions": "Aktibong mga produksyon",
|
||||
"productionsHint": "Mga produksyon nga nagdagan ug hapit nang mahuman o manginahanglan og pagtan-aw.",
|
||||
"stock": "Mga posisyon sa stock",
|
||||
"stockHint": "Mubo nga tan-aw sa mga baligya ug stock sa tanang rehiyon.",
|
||||
"open": "Ablihi"
|
||||
}
|
||||
},
|
||||
"health": {
|
||||
"amazing": "Maayo kaayo",
|
||||
"good": "Maayo",
|
||||
"normal": "Normal",
|
||||
"bad": "Dili maayo",
|
||||
"very_bad": "Daotan kaayo"
|
||||
},
|
||||
"moneyHistory": {
|
||||
"title": "Kasaysayan sa kuwarta",
|
||||
"filter": "Filter",
|
||||
"search": "I-apply ang filter",
|
||||
"activity": "Kalihokan",
|
||||
"moneyBefore": "Kuwarta sa wala pa ang transaksyon",
|
||||
"moneyAfter": "Kuwarta human sa transaksyon",
|
||||
"changeValue": "Kausaban sa bili",
|
||||
"time": "Oras",
|
||||
"prev": "Nangagi",
|
||||
"next": "Sunod",
|
||||
"graph": {
|
||||
"open": "Ipakita ang graph",
|
||||
"title": "Kuwarta sa paglabay sa panahon",
|
||||
"close": "Isira",
|
||||
"loading": "Nag-load sa history...",
|
||||
"noData": "Walay entry sa napiling panahon.",
|
||||
"yesterday": "Kagahapon",
|
||||
"range": {
|
||||
"label": "Sakop",
|
||||
"today": "Karon",
|
||||
"24h": "Kataposang 24 ka oras",
|
||||
"week": "Kataposang semana",
|
||||
"month": "Kataposang bulan",
|
||||
"year": "Kataposang tuig",
|
||||
"all": "Tibuok history"
|
||||
}
|
||||
},
|
||||
"activities": {
|
||||
"Product sale": "Pagbaligya sa produkto",
|
||||
"Production cost": "Gasto sa produksyon",
|
||||
"Sell all products": "Ibaligya ang tanang produkto",
|
||||
"sell products": "Ibaligya ang mga produkto",
|
||||
"director starts production": "Nagsugod ang direktor og produksyon",
|
||||
"director payed out": "Nabayran ang sweldo sa direktor",
|
||||
"create_branch": "Nahimo ang branch",
|
||||
"buy_vehicles": "Napamalit ang transport vehicles",
|
||||
"build_vehicles": "Nabuhat ang transport vehicles",
|
||||
"transport": "Transport",
|
||||
"Marriage cost": "Gasto sa kasal",
|
||||
"marriage_gift": "Regalo sa asawa/bana",
|
||||
"Gift cost": "Gasto sa regalo",
|
||||
"lover maintenance": "Maintenance sa karelasyon",
|
||||
"servants_monthly": "Nabayran ang mga sulugoon",
|
||||
"servants_hired": "Nakuha ang mga sulugoon",
|
||||
"household_order": "Gi-order ang household",
|
||||
"housebuy": "Pagpalit og balay",
|
||||
"Baptism": "Bunyag",
|
||||
"credit taken": "Nakuhaan og credit",
|
||||
"new nobility title": "Bag-ong titulo sa kadungganan",
|
||||
"partyOrder": "Gi-order ang party",
|
||||
"renovation_all": "Kompleto nga gi-renovate ang balay"
|
||||
}
|
||||
},
|
||||
"house": {
|
||||
"title": "Balay",
|
||||
"debtorsPrison": {
|
||||
"houseWarning": "Samtang nagkadako ang kalangan sa utang, nagkataas ang risgo sa pagsakmit ug pinugos nga pagkawala sa balay.",
|
||||
"houseRisk": "Ang imong balay apil na karon sa posibleng pinugos nga liquidation."
|
||||
},
|
||||
"statusreport": "Kondisyon sa balay",
|
||||
"element": "Elemento",
|
||||
"state": "Kondisyon",
|
||||
"buyablehouses": "Pagpalit og balay",
|
||||
"buy": "Palita",
|
||||
"price": "Presyo sa pagpalit",
|
||||
"worth": "Nabiling bili",
|
||||
"sell": "Ibaligya",
|
||||
"sellConfirm": "Tinuod ba nga gusto nimong ibaligya ang imong balay?",
|
||||
"sellSuccess": "Nabaligya na ang balay.",
|
||||
"sellError": "Dili mabaligya ang balay.",
|
||||
"buySuccess": "Napamalit na ang balay.",
|
||||
"buyError": "Dili mapalit ang balay.",
|
||||
"renovate": "Renovate",
|
||||
"renovateAll": "I-renovate tanan",
|
||||
"servants": {
|
||||
"title": "Mga sulugoon",
|
||||
"description": "Dumala sa household staff, kahapsay ug balik-balik nga gasto sa imong panimalay.",
|
||||
"count": "Ihap sa mga sulugoon",
|
||||
"expectedRange": "Gipaabot nga sakop",
|
||||
"monthlyCost": "Binuwan nga gasto",
|
||||
"quality": "Kalidad",
|
||||
"householdOrder": "Household order",
|
||||
"payLevel": "Antas sa bayad"
|
||||
},
|
||||
"status": {
|
||||
"roofCondition": "Atop",
|
||||
"wallCondition": "Mga bungbong",
|
||||
"floorCondition": "Salog",
|
||||
"windowCondition": "Mga bintana"
|
||||
},
|
||||
"type": {
|
||||
"backyard_room": "Kuwarto sa likod-balay",
|
||||
"wooden_house": "Kahoyng balay",
|
||||
"straw_hut": "Payag nga kugon",
|
||||
"family_house": "Balay-pamilya",
|
||||
"townhouse": "Townhouse"
|
||||
}
|
||||
},
|
||||
"newdirector": {
|
||||
"title": "Bag-ong direktor",
|
||||
"age": "Edad",
|
||||
"salary": "Sweldo",
|
||||
"skills": "Kahanas",
|
||||
"product": "Produkto",
|
||||
"knowledge": "Kahibalo",
|
||||
"hire": "Kuhon",
|
||||
"noProposals": "Walay available nga mga kandidato alang sa direktor."
|
||||
},
|
||||
"branch": {
|
||||
"title": "Branch",
|
||||
"heroEyebrow": "Branch",
|
||||
"heroIntro": "Produksyon, storage, pagbaligya ug transport sa usa ka control area nga naa sa kalibotan sa duwa.",
|
||||
"debtorsPrison": {
|
||||
"branchLocked": "Samtang naa sa debtors' prison, gi-block ang bag-ong mga lakang pang-ekonomiya.",
|
||||
"branchRisk": "Ang imong kalangan sa utang nagbutang sa imong mga branch, sakyanan ug gitigom nga mga butang sa peligro.",
|
||||
"selectionBlocked": "Gi-block ang bag-ong pagpamuhunan samtang napriso tungod sa utang."
|
||||
},
|
||||
"currentCertificate": "Karon nga sertipiko",
|
||||
"certificate": {
|
||||
"title": "Mga product unlock",
|
||||
"description": "Nagpakita kung unsang mga produkto ang ma-unlock sa imong karon nga sertipiko ug unsa ang madugang sa sunod nga level.",
|
||||
"currentUnlocks": "Karon nga na-unlock",
|
||||
"nextUnlocks": "Bag-o sa level {level}"
|
||||
},
|
||||
"selection": {
|
||||
"title": "Pagpili sa branch",
|
||||
"selected": "Napiling branch",
|
||||
"placeholder": "Wala pay napiling branch",
|
||||
"selectedcity": "Napiling siyudad",
|
||||
"weather": "Karon nga panahon"
|
||||
},
|
||||
"director": {
|
||||
"income": "Kita",
|
||||
"incomeUpdated": "Malampuson nga na-update ang sweldo.",
|
||||
"starttransport": "Makapagsugod og transport"
|
||||
},
|
||||
"sale": {
|
||||
"runningGuards": "Mga guwardiya"
|
||||
},
|
||||
"production": {
|
||||
"title": "Produksyon",
|
||||
"info": "Mga detalye bahin sa produksyon sa branch.",
|
||||
"selectProduct": "Pilia ang produkto",
|
||||
"quantity": "Kadaghanon",
|
||||
"storageAvailable": "Libre nga storage",
|
||||
"cost": "Gasto",
|
||||
"duration": "Kadugayon",
|
||||
"revenue": "Kita",
|
||||
"start": "Sugdi ang produksyon",
|
||||
"success": "Malampuson nga nasugdan ang produksyon!",
|
||||
"error": "Sayop sa pagsugod sa produksyon.",
|
||||
"minutes": "Mga minuto",
|
||||
"ending": "Matapos sa:",
|
||||
"time": "Oras",
|
||||
"current": "Nagpadagan nga mga produksyon",
|
||||
"product": "Produkto",
|
||||
"remainingTime": "Nabiling oras (segundo)",
|
||||
"status": "Status",
|
||||
"sleep": "Gi-pause",
|
||||
"active": "Aktibo",
|
||||
"noProductions": "Walay nagdagan nga produksyon."
|
||||
},
|
||||
"columns": {
|
||||
"city": "Siyudad",
|
||||
"type": "Type"
|
||||
},
|
||||
"types": {
|
||||
"production": "Produksyon",
|
||||
"store": "Pagbaligya",
|
||||
"fullstack": "Produksyon uban sa pagbaligya"
|
||||
},
|
||||
"revenue": {
|
||||
"title": "Kita sa produkto",
|
||||
"product": "Produkto",
|
||||
"absolute": "Kita (absoluto)",
|
||||
"perMinute": "Kita kada minuto",
|
||||
"expand": "Ipakita ang kita",
|
||||
"collapse": "Tagoa ang kita",
|
||||
"knowledge": "Kahibalo sa produkto",
|
||||
"profitAbsolute": "Tibuok ganansya",
|
||||
"profitPerMinute": "Ganansya kada minuto",
|
||||
"betterPrices": "Mas maayong presyo sa ubang lugar"
|
||||
},
|
||||
"vehicles": {
|
||||
"cargo_cart": "Cargo cart",
|
||||
"ox_cart": "Kariton nga baka",
|
||||
"small_carriage": "Gamayang karwahe",
|
||||
"large_carriage": "Dako nga karwahe",
|
||||
"four_horse_carriage": "Upat-ka-kabayo nga karwahe",
|
||||
"raft": "Balsa",
|
||||
"sailing_ship": "Barko nga layag"
|
||||
},
|
||||
"transport": {
|
||||
"guardCount": "Mga guwardiya",
|
||||
"guardHint": "Dugang nga gasto para sa mga guwardiya: {cost}"
|
||||
},
|
||||
"tabs": {
|
||||
"director": "Direktor",
|
||||
"inventory": "Inventory",
|
||||
"production": "Produksyon",
|
||||
"storage": "Storage",
|
||||
"transport": "Transport",
|
||||
"taxes": "Mga buhis"
|
||||
}
|
||||
},
|
||||
"nobility": {
|
||||
"highestPoliticalOffice": "Pinakataas nga politikal nga opisina",
|
||||
"highestOfficeAny": "Pinakataas nga opisina sa kinatibuk-an",
|
||||
"none": "wala",
|
||||
"cooldown": "Makapaningkamot ka pag-usab sa {date}."
|
||||
},
|
||||
"mood": {
|
||||
"happy": "Malipayon",
|
||||
"sad": "Masulub-on",
|
||||
"angry": "Masuko",
|
||||
"calm": "Kalma",
|
||||
"nervous": "Nerbiyos",
|
||||
"excited": "Excited",
|
||||
"bored": "Gikapoy",
|
||||
"fearful": "Nahadlok",
|
||||
"confident": "Masaligon",
|
||||
"curious": "Interesado"
|
||||
},
|
||||
"character": {
|
||||
"brave": "Maisog",
|
||||
"kind": "Maayo",
|
||||
"greedy": "Hakog",
|
||||
"wise": "Maalamon",
|
||||
"loyal": "Matinumanon",
|
||||
"cunning": "Tig-ihap",
|
||||
"generous": "Mapinanggaon",
|
||||
"arrogant": "Mapahitas-on",
|
||||
"honest": "Matinuoron",
|
||||
"ambitious": "Ambisyoso"
|
||||
},
|
||||
"healthview": {
|
||||
"title": "Panglawas",
|
||||
"age": "Edad",
|
||||
"status": "Status sa panglawas",
|
||||
"measuresTaken": "Mga gihimong lakang",
|
||||
"measure": "Lakang",
|
||||
"date": "Petsa",
|
||||
"cost": "Gasto",
|
||||
"success": "Kalampusan",
|
||||
"selectMeasure": "Pilia ang lakang",
|
||||
"perform": "Buhata",
|
||||
"choose": "Palihog pagpili",
|
||||
"nextMeasureAt": "Sunod nga lakang gikan sa"
|
||||
},
|
||||
"branchProduction": {
|
||||
"storageAvailable": "Libre nga storage"
|
||||
},
|
||||
"politics": {
|
||||
"title": "Politika",
|
||||
"tabs": {
|
||||
"current": "Karon nga posisyon",
|
||||
"upcoming": "Umaabot nga mga posisyon",
|
||||
"elections": "Mga eleksiyon"
|
||||
},
|
||||
"bookmarkCandidate": "Timan-i kining kandidatura",
|
||||
"voteError": "Sayop sa paghatag sa boto",
|
||||
"voteAllError": "Sayop sa paghatag sa mga boto",
|
||||
"applyError": "Dili mapadala ang aplikasyon."
|
||||
},
|
||||
"family": {
|
||||
"title": "Pamilya",
|
||||
"heroIntro": "Mga relasyon, mga anak ug pag-uswag — gihikay pinaagi sa seksyon sa ubos.",
|
||||
"summary": {
|
||||
"partnerChip": "Kapikas",
|
||||
"childrenChip": "Mga anak",
|
||||
"loversChip": "Mga affair",
|
||||
"proposalsAvailable": "Adunay proposal",
|
||||
"noPartner": "Walay kapikas"
|
||||
},
|
||||
"tabs": {
|
||||
"partner": "Kapikas ug kasal",
|
||||
"children": "Mga anak",
|
||||
"lovers": "Mga affair"
|
||||
}
|
||||
},
|
||||
"church": {
|
||||
"title": "Simbahan",
|
||||
"tabs": {
|
||||
"baptism": "Bunyag",
|
||||
"current": "Karon nga mga posisyon",
|
||||
"available": "Available nga mga posisyon",
|
||||
"applications": "Mga aplikasyon"
|
||||
}
|
||||
},
|
||||
"bank": {
|
||||
"title": "Bangko",
|
||||
"account": {
|
||||
"title": "Account",
|
||||
"balance": "Balanse",
|
||||
"totalDebt": "Tibuok utang",
|
||||
"maxCredit": "Pinakataas nga credit",
|
||||
"availableCredit": "Available nga credit"
|
||||
},
|
||||
"credits": {
|
||||
"title": "Mga credit",
|
||||
"none": "Wala kay mga credit karon.",
|
||||
"amount": "Kantidad",
|
||||
"remaining": "Nabilin",
|
||||
"interestRate": "Interest rate"
|
||||
}
|
||||
},
|
||||
"reputation": {
|
||||
"title": "Reputasyon",
|
||||
"overview": {
|
||||
"title": "Overview",
|
||||
"current": "Karon nga reputasyon"
|
||||
},
|
||||
"actions": {
|
||||
"title": "Mga aksyon sa reputasyon",
|
||||
"description": "Makabuhat ka og lainlaing aksyon aron mapauswag ang imong reputasyon.",
|
||||
"none": "Walay available nga aksyon sa reputasyon.",
|
||||
"action": "Aksyon",
|
||||
"cost": "Gasto",
|
||||
"gain": "Nadugang",
|
||||
"timesUsed": "Gigamit",
|
||||
"execute": "Buhata"
|
||||
},
|
||||
"party": {
|
||||
"title": "Mga party",
|
||||
"totalCost": "Tibuok gasto",
|
||||
"order": "Umara og party",
|
||||
"inProgress": "Mga party nga giandam",
|
||||
"completed": "Nahuman nga mga party"
|
||||
}
|
||||
},
|
||||
"underground": {
|
||||
"title": "Underground",
|
||||
"tabs": {
|
||||
"activities": "Mga kalihokan",
|
||||
"attacks": "Mga pag-atake"
|
||||
},
|
||||
"activities": {
|
||||
"none": "Walay available nga kalihokan.",
|
||||
"create": "Paghimo og bag-ong kalihokan",
|
||||
"type": "Type sa kalihokan",
|
||||
"victim": "Target nga tawo",
|
||||
"cost": "Gasto",
|
||||
"status": "Status"
|
||||
},
|
||||
"attacks": {
|
||||
"target": "Tig-atake",
|
||||
"date": "Petsa",
|
||||
"success": "Kalampusan",
|
||||
"none": "Walay natala nga mga pag-atake."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
23
frontend/src/i18n/locales/ceb/friends.json
Normal file
23
frontend/src/i18n/locales/ceb/friends.json
Normal file
@@ -0,0 +1,23 @@
|
||||
{
|
||||
"friends": {
|
||||
"title": "Mga higala",
|
||||
"tabs": {
|
||||
"existing": "Naa na",
|
||||
"rejected": "Gibalibaran",
|
||||
"pending": "Naghulat",
|
||||
"requested": "Gihangyo"
|
||||
},
|
||||
"actions": {
|
||||
"end": "Tapusa",
|
||||
"accept": "Dawata",
|
||||
"reject": "Balibari",
|
||||
"withdraw": "Bawia"
|
||||
},
|
||||
"headers": {
|
||||
"name": "Ngalan",
|
||||
"age": "Edad",
|
||||
"gender": "Gender",
|
||||
"actions": "Mga aksyon"
|
||||
}
|
||||
}
|
||||
}
|
||||
117
frontend/src/i18n/locales/ceb/general.json
Normal file
117
frontend/src/i18n/locales/ceb/general.json
Normal file
@@ -0,0 +1,117 @@
|
||||
{
|
||||
"welcome": "Maayong pag-abot sa YourPart",
|
||||
"imprint": {
|
||||
"title": "Imprint",
|
||||
"button": "Imprint"
|
||||
},
|
||||
"dataPrivacy": {
|
||||
"title": "Patakaran sa pagpanalipod sa datos",
|
||||
"button": "Pagpanalipod sa datos"
|
||||
},
|
||||
"contact": {
|
||||
"title": "Kontak",
|
||||
"button": "Kontak"
|
||||
},
|
||||
"error-title": "Sayop",
|
||||
"warning-title": "Pasidaan",
|
||||
"info-title": "Impormasyon",
|
||||
"general": {
|
||||
"loading": "Nagkarga...",
|
||||
"back": "Balik",
|
||||
"cancel": "Kanselahon",
|
||||
"ok": "OK",
|
||||
"yes": "Oo",
|
||||
"no": "Dili"
|
||||
},
|
||||
"OK": "Ok",
|
||||
"Cancel": "Kanselahon",
|
||||
"yes": "Oo",
|
||||
"no": "Dili",
|
||||
"message": {
|
||||
"close": "Isira"
|
||||
},
|
||||
"gender": {
|
||||
"male": "Lalaki",
|
||||
"female": "Babaye",
|
||||
"transmale": "Trans nga lalaki",
|
||||
"transfemale": "Trans nga babaye",
|
||||
"nonbinary": "Dili binaryo"
|
||||
},
|
||||
"common": {
|
||||
"edit": "Usba",
|
||||
"delete": "Tangtanga",
|
||||
"create": "Paghimo",
|
||||
"update": "I-update",
|
||||
"save": "I-save",
|
||||
"add": "Idugang",
|
||||
"cancel": "Kanselahon",
|
||||
"yes": "Oo",
|
||||
"no": "Dili"
|
||||
},
|
||||
"sectionBar": {
|
||||
"sections": {
|
||||
"default": "Seksyon",
|
||||
"falukant": "Falukant",
|
||||
"vocab": "Trainer sa bokabularyo",
|
||||
"forum": "Forum",
|
||||
"community": "Komunidad",
|
||||
"settings": "Mga setting",
|
||||
"administration": "Administrasyon",
|
||||
"minigames": "Mga minigame",
|
||||
"personal": "Personal",
|
||||
"blog": "Blog"
|
||||
},
|
||||
"titles": {
|
||||
"friends": "Mga higala",
|
||||
"guestbook": "Guestbook",
|
||||
"search": "Pagpangita",
|
||||
"gallery": "Galeriya",
|
||||
"forum": "Forum",
|
||||
"topic": "Hilisgutan",
|
||||
"diary": "Talaarawan",
|
||||
"languages": "Mga pinulongan",
|
||||
"newLanguage": "Bag-ong pinulongan",
|
||||
"subscribeLanguage": "Mag-subscribe sa pinulongan",
|
||||
"language": "Pinulongan",
|
||||
"chapter": "Kapitulo",
|
||||
"courses": "Mga kurso",
|
||||
"course": "Kurso",
|
||||
"lesson": "Leksiyon",
|
||||
"createCharacter": "Paghimo og karakter",
|
||||
"overview": "Kinatibuk-an",
|
||||
"branch": "Sangang opisina",
|
||||
"moneyHistory": "Kasaysayan sa kuwarta",
|
||||
"family": "Pamilya",
|
||||
"house": "Balay",
|
||||
"nobility": "Kadungganan",
|
||||
"reputation": "Dungog",
|
||||
"church": "Simbahan",
|
||||
"education": "Edukasyon",
|
||||
"bank": "Bangko",
|
||||
"directors": "Mga direktor",
|
||||
"health": "Panglawas",
|
||||
"politics": "Politika",
|
||||
"underground": "Ilalom nga kalibutan",
|
||||
"personalSettings": "Personal nga datos",
|
||||
"viewSettings": "Panagway",
|
||||
"sexualitySettings": "Sekswalidad",
|
||||
"flirtSettings": "Flirt",
|
||||
"accountSettings": "Account",
|
||||
"languageAssistantSettings": "Language assistant",
|
||||
"interests": "Mga interes",
|
||||
"adminInterests": "Pagdumala sa interes",
|
||||
"adminUsers": "Mga user",
|
||||
"adminUserStatistics": "Estadistika sa user",
|
||||
"adminContacts": "Mga hangyo sa kontak",
|
||||
"adminUserRights": "Mga katungod",
|
||||
"adminForums": "Pagdumala sa forum",
|
||||
"adminChatRooms": "Mga chat room",
|
||||
"adminFalukantUsers": "Mga user sa Falukant",
|
||||
"adminFalukantMap": "Mapa sa Falukant",
|
||||
"adminCreateNpc": "Paghimo og NPC",
|
||||
"adminMinigames": "Pagdumala sa Match3",
|
||||
"adminTaxiTools": "Mga himan sa taxi",
|
||||
"adminServicesStatus": "Status sa serbisyo"
|
||||
}
|
||||
}
|
||||
}
|
||||
5
frontend/src/i18n/locales/ceb/header.json
Normal file
5
frontend/src/i18n/locales/ceb/header.json
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"logo": "Logo",
|
||||
"title": "YourPart",
|
||||
"advertisement": "Anunsyo"
|
||||
}
|
||||
46
frontend/src/i18n/locales/ceb/home.json
Normal file
46
frontend/src/i18n/locales/ceb/home.json
Normal file
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"home": {
|
||||
"betaNoticeLabel": "Pahibalo sa beta:",
|
||||
"betaNoticeText": "Ang YourPart padayon pang gihimo. Adunay mga feature nga wala pa mahuman, adunay impormasyon nga kulang pa, ug posible pa nga adunay mga kausaban.",
|
||||
"nologin": {
|
||||
"welcome": "Maayong pag-abot sa yourPart",
|
||||
"description": "Ang yourPart usa ka social network diin makapangita ka og mga higala ug makaila og bag-ong mga tawo. Makapaambit ka og mga hulagway ug makapili kinsa ang makakita niini. Makapadala usab ka og mga mensahe ug makig-chat sa dagkong public rooms o sa gamay nga random chat.",
|
||||
"introHtml": "Ang YourPart usa ka nagtubo nga plataporma nga naghiusa sa community features, real-time chat, forum, social network nga adunay photo gallery, ug sa city-builder game nga <em>Falukant</em>. Beta pa karon ang site ug padayon pa namong palapdan ang features, sulod ug kalig-on.",
|
||||
"expected": {
|
||||
"title": "Unsa ang imong mapaabot",
|
||||
"items": {
|
||||
"chat": "<strong>Chat</strong>: Mga public room, random nga panagkita ug mga color adjustment.",
|
||||
"social": "<strong>Social network</strong>: Profile, mga higala, photo gallery nga adunay visibility controls.",
|
||||
"forum": "<strong>Forum</strong>: Paghimo og mga topic, pagsulat og mga post, role-based moderation.",
|
||||
"falukant": "<strong>Falukant</strong>: Ekonomiya ug kinabuhi - pagdumala sa mga sanga, paghimo, pagtipig ug pagbaligya.",
|
||||
"minigames": "<strong>Mini games</strong>: pananglitan Match-3 levels para sa mubo nga kalingawan.",
|
||||
"multilingual": "<strong>Daghang pinulongan</strong>: Aleman/Iningles - padayon pang gidugangan ang sulod."
|
||||
}
|
||||
},
|
||||
"falukantShort": {
|
||||
"title": "Falukant - sa mubo",
|
||||
"text": "Sa Falukant, magdumala ka og negosyo, motukod og kahibalo, mo-optimize sa produksyon ug baligya, motan-aw sa presyo ug motubag sa mga panghitabo. Ang mga notification motug-an sa mga kausaban sa status sa tinuod nga oras."
|
||||
},
|
||||
"privacyBeta": {
|
||||
"title": "Privacy ug beta status",
|
||||
"text": "Beta pa ang YourPart. Posible pa ang mga kausaban, outage ug kulang nga mga hubad. Importante kanamo ang privacy ug transparency; dugang impormasyon moabot samtang nagpadayon ang beta."
|
||||
},
|
||||
"getStarted": {
|
||||
"title": "Sugdi na",
|
||||
"text": "Pwede na nimo gamiton, sulayan ug hatagan og feedback. Pagrehistro pinaagi sa “{register}” o sugdi ang random chat."
|
||||
},
|
||||
"randomchat": "Random chat",
|
||||
"startrandomchat": "Sugdi ang random chat",
|
||||
"login": {
|
||||
"name": "Login name",
|
||||
"namedescription": "Isulod ang imong username",
|
||||
"password": "Password",
|
||||
"passworddescription": "Isulod ang imong password",
|
||||
"lostpassword": "Nakalimot sa password",
|
||||
"register": "Pagrehistro sa yourPart",
|
||||
"stayLoggedIn": "Magpabiling naka-login",
|
||||
"submit": "Mo-login"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
8
frontend/src/i18n/locales/ceb/message.json
Normal file
8
frontend/src/i18n/locales/ceb/message.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"message": {
|
||||
"title": "Mensahe",
|
||||
"close": "Isira",
|
||||
"test": "Nagtrabaho ang test",
|
||||
"success": "Malampuson ang aksyon."
|
||||
}
|
||||
}
|
||||
107
frontend/src/i18n/locales/ceb/minigames.json
Normal file
107
frontend/src/i18n/locales/ceb/minigames.json
Normal file
@@ -0,0 +1,107 @@
|
||||
{
|
||||
"minigames": {
|
||||
"title": "Minigames",
|
||||
"description": "Susiha ang koleksiyon sa makalingaw nga minigames!",
|
||||
"play": "Dula",
|
||||
"backToGames": "Balik sa mga dula",
|
||||
"comingSoon": {
|
||||
"title": "Moabot na",
|
||||
"description": "Mas daghang nindot nga mga dula ang gihimo pa!"
|
||||
},
|
||||
"match3": {
|
||||
"title": "Match 3 - Kampanya sa mga hiyas",
|
||||
"description": "Ipahiusa ang tulo o labaw pa ka magkaparehong hiyas aron makakuha og puntos!",
|
||||
"campaignDescription": "Dulaa ang tanang level ug tigoma ang mga bituon!",
|
||||
"gameStats": "Mga estadistika sa dula",
|
||||
"score": "Puntos",
|
||||
"moves": "Mga lihok",
|
||||
"currentLevel": "Karon nga level",
|
||||
"level": "Level",
|
||||
"stars": "Mga bituon",
|
||||
"movesLeft": "Nabiling mga lihok",
|
||||
"restartLevel": "Sugdi pag-usab ang level",
|
||||
"pause": "Pause",
|
||||
"resume": "Padayona",
|
||||
"paused": "Gi-pause ang dula",
|
||||
"levelComplete": "Nahuman ang level!",
|
||||
"levelScore": "Puntos sa level",
|
||||
"movesUsed": "Gigamit nga mga lihok",
|
||||
"starsEarned": "Nakuha nga mga bituon",
|
||||
"nextLevel": "Sunod nga level",
|
||||
"campaignComplete": "Nahuman ang kampanya!",
|
||||
"totalScore": "Kinatibuk-ang puntos",
|
||||
"totalStars": "Kinatibuk-ang mga bituon",
|
||||
"levelsCompleted": "Nahuman nga mga level",
|
||||
"restartCampaign": "Sugdi pag-usab ang kampanya",
|
||||
"nextStep": "Sunod nga lakang",
|
||||
"objectivesCollapse": "I-collapse ang mga tumong",
|
||||
"objectivesShow": "Ipakita ang mga tumong",
|
||||
"objectives": "Mga tumong",
|
||||
"loadingBoard": "Ginaandam ang game board...",
|
||||
"loadingHint": "Ang datos sa level, mga tumong ug layout sa board gi-sync pa."
|
||||
},
|
||||
"taxi": {
|
||||
"title": "Taxi Simulator",
|
||||
"description": "Pagdrayb sa mga pasahero palibot sa siyudad ug pagpangwarta!",
|
||||
"gameStats": "Mga estadistika sa dula",
|
||||
"score": "Puntos",
|
||||
"money": "Kuwarta",
|
||||
"passengers": "Mga pasahero",
|
||||
"currentLevel": "Karon nga level",
|
||||
"level": "Level",
|
||||
"fuel": "Gasolina",
|
||||
"fuelLeft": "Nabiling gasolina",
|
||||
"restartLevel": "Sugdi pag-usab ang level",
|
||||
"pause": "Pause",
|
||||
"resume": "Padayona",
|
||||
"paused": "Gi-pause ang dula",
|
||||
"levelComplete": "Nahuman ang level!",
|
||||
"levelScore": "Puntos sa level",
|
||||
"moneyEarned": "Nakwarta",
|
||||
"passengersDelivered": "Nahatud nga mga pasahero",
|
||||
"nextLevel": "Sunod nga level",
|
||||
"campaignComplete": "Nahuman ang kampanya!",
|
||||
"totalScore": "Kinatibuk-ang puntos",
|
||||
"totalMoney": "Kinatibuk-ang kuwarta",
|
||||
"levelsCompleted": "Nahuman nga mga level",
|
||||
"restartCampaign": "Sugdi pag-usab ang kampanya",
|
||||
"pickupPassenger": "Sakya ang pasahero",
|
||||
"deliverPassenger": "Ihatod ang pasahero",
|
||||
"refuel": "Magpuno og gasolina",
|
||||
"startEngine": "Paandara ang makina",
|
||||
"stopEngine": "Patya ang makina",
|
||||
"controls": "Kontrol",
|
||||
"accelerate": "Paspasa",
|
||||
"brake": "Prino",
|
||||
"steerRight": "Liko sa tuo",
|
||||
"steerLeft": "Liko sa wala",
|
||||
"goals": "Mga tumong",
|
||||
"avoidCollisions": "Likayi ang bangga sa ubang sakyanan",
|
||||
"streetNames": "Mga ngalan sa dalan",
|
||||
"remainingVehicles": "Nabiling mga sakyanan",
|
||||
"fuelTitle": "Gasolina",
|
||||
"pointsTitle": "Puntos",
|
||||
"speedViolations": "Mga lapas sa speed limit",
|
||||
"redLightsPassed": "Mga pulang suga nga nalapas",
|
||||
"highscore": "Highscore",
|
||||
"topPlayers": "Top 20 nga mga player",
|
||||
"loadingHighscore": "Nag-load sa highscore...",
|
||||
"noHighscore": "Wala pay highscore",
|
||||
"pointsShort": "pts",
|
||||
"backToGame": "Balik sa dula",
|
||||
"minimap": "Minimap",
|
||||
"loadedPassengers": "Mga pasahero sulod sa taxi",
|
||||
"waitingPassengers": "Naghulat nga mga pasahero",
|
||||
"noPassengersInTaxi": "Walay pasahero sulod sa taxi",
|
||||
"noWaitingPassengers": "Walay naghulat nga pasahero",
|
||||
"name": "Ngalan",
|
||||
"destination": "Padulngan",
|
||||
"bonus": "Bonus",
|
||||
"time": "Oras",
|
||||
"crash": {
|
||||
"title": "Bangga!",
|
||||
"message": "Naaksidente ka! Mga crash: {crashes}"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
119
frontend/src/i18n/locales/ceb/navigation.json
Normal file
119
frontend/src/i18n/locales/ceb/navigation.json
Normal file
@@ -0,0 +1,119 @@
|
||||
{
|
||||
"navigation": {
|
||||
"home": "Sinugdanan",
|
||||
"logout": "Pag-logout",
|
||||
"friends": "Mga higala",
|
||||
"socialnetwork": "Tigomanan",
|
||||
"chats": "Mga chat",
|
||||
"falukant": "Falukant",
|
||||
"minigames": "Mga minigame",
|
||||
"personal": "Personal",
|
||||
"settings": "Mga setting",
|
||||
"administration": "Pagdumala",
|
||||
"m-chats": {
|
||||
"multiChat": "Multiuser chat",
|
||||
"randomChat": "Random single chat",
|
||||
"eroticChat": "Erotik chat"
|
||||
},
|
||||
"m-socialnetwork": {
|
||||
"guestbook": "Guestbook",
|
||||
"blog": "Blog",
|
||||
"usersearch": "Pagpangita og user",
|
||||
"forum": "Forum",
|
||||
"gallery": "Galeriya",
|
||||
"sprachenlernen": "Pagtuon og pinulongan",
|
||||
"blockedUsers": "Mga gi-block nga user",
|
||||
"oneTimeInvitation": "Usa ka higayon nga imbitasyon",
|
||||
"diary": "Talaarawan",
|
||||
"erotic": "Erotik",
|
||||
"m-erotic": {
|
||||
"pictures": "Mga hulagway",
|
||||
"videos": "Mga video"
|
||||
},
|
||||
"m-sprachenlernen": {
|
||||
"vocabtrainer": "Trainer sa bokabularyo",
|
||||
"sprachkurse": "Mga kurso sa pinulongan",
|
||||
"m-vocabtrainer": {
|
||||
"newLanguage": "Bag-ong pinulongan"
|
||||
}
|
||||
}
|
||||
},
|
||||
"m-minigames": {
|
||||
"match3": "Match 3 - Hiyas",
|
||||
"taxi": "Taxi simulator"
|
||||
},
|
||||
"m-personal": {
|
||||
"sprachenlernen": "Pagtuon og pinulongan",
|
||||
"calendar": "Kalendaryo",
|
||||
"m-sprachenlernen": {
|
||||
"vocabtrainer": "Trainer sa bokabularyo",
|
||||
"sprachkurse": "Mga kurso sa pinulongan",
|
||||
"m-vocabtrainer": {
|
||||
"newLanguage": "Bag-ong pinulongan"
|
||||
}
|
||||
}
|
||||
},
|
||||
"m-settings": {
|
||||
"homepage": "Sinugdanan",
|
||||
"account": "Account",
|
||||
"personal": "Personal",
|
||||
"view": "Panagway",
|
||||
"flirt": "Flirt",
|
||||
"interests": "Mga interes",
|
||||
"notifications": "Mga pahibalo",
|
||||
"sexuality": "Sekswalidad",
|
||||
"languageAssistant": "Language assistant"
|
||||
},
|
||||
"m-administration": {
|
||||
"contactrequests": "Mga hangyo sa kontak",
|
||||
"users": "Mga user",
|
||||
"userrights": "Mga katungod sa user",
|
||||
"m-users": {
|
||||
"userlist": "Lista sa user",
|
||||
"adultverification": "Mga erotik nga pag-apruba",
|
||||
"eroticmoderation": "Erotik nga moderasyon",
|
||||
"userstatistics": "Estadistika sa user",
|
||||
"userrights": "Mga katungod sa user"
|
||||
},
|
||||
"forum": "Forum",
|
||||
"interests": "Mga interes",
|
||||
"falukant": "Falukant",
|
||||
"m-falukant": {
|
||||
"logentries": "Mga log entry",
|
||||
"edituser": "Usba ang user",
|
||||
"database": "Database",
|
||||
"mapEditor": "Editor sa mapa",
|
||||
"createNPC": "Paghimo og NPC"
|
||||
},
|
||||
"minigames": "Mga minigame",
|
||||
"m-minigames": {
|
||||
"match3": "Mga level sa Match3",
|
||||
"taxiTools": "Mga himan sa taxi"
|
||||
},
|
||||
"chatrooms": "Mga chat room",
|
||||
"servicesStatus": "Status sa serbisyo"
|
||||
},
|
||||
"m-friends": {
|
||||
"manageFriends": "Dumala sa mga higala",
|
||||
"chat": "Makig-chat",
|
||||
"profile": "Profile"
|
||||
},
|
||||
"m-falukant": {
|
||||
"create": "Paghimo",
|
||||
"overview": "Kinatibuk-an",
|
||||
"towns": "Mga sangang opisina",
|
||||
"factory": "Produksyon",
|
||||
"family": "Pamilya",
|
||||
"house": "Balay",
|
||||
"darknet": "Ilalom nga kalibutan",
|
||||
"reputation": "Dungog",
|
||||
"moneyhistory": "Agos sa kuwarta",
|
||||
"nobility": "Sosyal nga kahimtang",
|
||||
"politics": "Politika",
|
||||
"education": "Edukasyon",
|
||||
"health": "Panglawas",
|
||||
"bank": "Bangko",
|
||||
"church": "Simbahan"
|
||||
}
|
||||
}
|
||||
}
|
||||
13
frontend/src/i18n/locales/ceb/passwordReset.json
Normal file
13
frontend/src/i18n/locales/ceb/passwordReset.json
Normal file
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"passwordReset": {
|
||||
"title": "I-reset ang password",
|
||||
"email": "Email",
|
||||
"reset": "I-reset",
|
||||
"success": "Kung naa ang email, nagpadala kami og mga instruksyon sa pag-reset.",
|
||||
"failure": "Napakyas ang pag-reset sa password. Palihog sulayi pag-usab unya.",
|
||||
"emailHint": "Among ipadala ang link sa naka-save nga email address.",
|
||||
"validation": {
|
||||
"invalidEmail": "Palihog isulod ang sakto nga email address."
|
||||
}
|
||||
}
|
||||
}
|
||||
79
frontend/src/i18n/locales/ceb/personal.json
Normal file
79
frontend/src/i18n/locales/ceb/personal.json
Normal file
@@ -0,0 +1,79 @@
|
||||
{
|
||||
"personal": {
|
||||
"calendar": {
|
||||
"title": "Kalendaryo",
|
||||
"today": "Karon",
|
||||
"newEntry": "Bag-ong entry",
|
||||
"editEntry": "Usba ang entry",
|
||||
"selectedDays": "{count} ka adlaw ang napili",
|
||||
"createEventForSelection": "Paghimo og event",
|
||||
"clearSelection": "Hawanon ang pinili",
|
||||
"allDay": "Tibuok adlaw",
|
||||
"views": {
|
||||
"month": "Bulan",
|
||||
"week": "Semana",
|
||||
"workweek": "Semana sa trabaho",
|
||||
"day": "Adlaw"
|
||||
},
|
||||
"weekdays": {
|
||||
"mon": "Lun",
|
||||
"tue": "Mar",
|
||||
"wed": "Miy",
|
||||
"thu": "Huw",
|
||||
"fri": "Biy",
|
||||
"sat": "Sab",
|
||||
"sun": "Dom"
|
||||
},
|
||||
"weekdaysFull": {
|
||||
"mon": "Lunes",
|
||||
"tue": "Martes",
|
||||
"wed": "Miyerkules",
|
||||
"thu": "Huwebes",
|
||||
"fri": "Biyernes",
|
||||
"sat": "Sabado",
|
||||
"sun": "Domingo"
|
||||
},
|
||||
"months": {
|
||||
"jan": "Enero",
|
||||
"feb": "Pebrero",
|
||||
"mar": "Marso",
|
||||
"apr": "Abril",
|
||||
"may": "Mayo",
|
||||
"jun": "Hunyo",
|
||||
"jul": "Hulyo",
|
||||
"aug": "Agosto",
|
||||
"sep": "Setyembre",
|
||||
"oct": "Oktubre",
|
||||
"nov": "Nobyembre",
|
||||
"dec": "Disyembre"
|
||||
},
|
||||
"categories": {
|
||||
"personal": "Personal",
|
||||
"work": "Trabaho",
|
||||
"family": "Pamilya",
|
||||
"health": "Panglawas",
|
||||
"birthday": "Adlawng natawhan",
|
||||
"holiday": "Holiday",
|
||||
"reminder": "Pahinumdom",
|
||||
"other": "Uban pa"
|
||||
},
|
||||
"form": {
|
||||
"title": "Pamagat",
|
||||
"titlePlaceholder": "Isulod ang pamagat...",
|
||||
"category": "Kategorya",
|
||||
"startDate": "Petsa sa pagsugod",
|
||||
"startTime": "Oras sa pagsugod",
|
||||
"endDate": "Petsa sa pagtapos",
|
||||
"endTime": "Oras sa pagtapos",
|
||||
"allDay": "Tibuok adlaw",
|
||||
"description": "Deskripsyon",
|
||||
"descriptionPlaceholder": "Opsyonal nga deskripsyon...",
|
||||
"save": "I-save",
|
||||
"cancel": "I-cancel",
|
||||
"delete": "Tangtanga",
|
||||
"saveError": "Sayop sa pagsave sa event",
|
||||
"deleteError": "Sayop sa pagtangtang sa event"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
28
frontend/src/i18n/locales/ceb/register.json
Normal file
28
frontend/src/i18n/locales/ceb/register.json
Normal file
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"register": {
|
||||
"title": "Pagrehistro sa yourPart",
|
||||
"email": "E-mail address",
|
||||
"username": "Username",
|
||||
"password": "Password",
|
||||
"repeatPassword": "Usba ang password",
|
||||
"language": "Pinulongan",
|
||||
"languages": {
|
||||
"en": "Iningles",
|
||||
"de": "Aleman",
|
||||
"ceb": "Bisaya"
|
||||
},
|
||||
"register": "Pagrehistro",
|
||||
"close": "Isira",
|
||||
"failure": "Adunay nahitabo nga sayop.",
|
||||
"success": "Malampuson kang narehistro. Palihog susiha ang imong email aron ma-activate ang imong account.",
|
||||
"passwordMismatch": "Dili magkapareho ang mga password.",
|
||||
"emailinuse": "Gigamit na daan ang email address.",
|
||||
"usernameinuse": "Dili magamit ang username.",
|
||||
"validation": {
|
||||
"invalidEmail": "Palihog isulod ang sakto nga email address.",
|
||||
"usernameTooShort": "Ang username kinahanglan adunay labing menos 3 ka karakter.",
|
||||
"passwordHint": "Kinahanglan labing menos 8 ka karakter.",
|
||||
"passwordTooShort": "Mubo ra ang password."
|
||||
}
|
||||
}
|
||||
}
|
||||
58
frontend/src/i18n/locales/ceb/settings.json
Normal file
58
frontend/src/i18n/locales/ceb/settings.json
Normal file
@@ -0,0 +1,58 @@
|
||||
{
|
||||
"settings": {
|
||||
"personal": {
|
||||
"title": "Personal nga datos",
|
||||
"label": {
|
||||
"language": "Pinulongan"
|
||||
},
|
||||
"tooltip": {
|
||||
"language": "Pinulongan"
|
||||
},
|
||||
"language": {
|
||||
"de": "Aleman",
|
||||
"en": "Iningles",
|
||||
"ceb": "Bisaya"
|
||||
}
|
||||
},
|
||||
"view": {
|
||||
"title": "Panagway"
|
||||
},
|
||||
"sexuality": {
|
||||
"title": "Sekswalidad"
|
||||
},
|
||||
"account": {
|
||||
"title": "Account",
|
||||
"heroEyebrow": "Settings",
|
||||
"heroIntro": "Atimana ang username, email, password ug visibility sa usa ka lugar.",
|
||||
"language": "Pinulongan",
|
||||
"username": "Username",
|
||||
"email": "E-mail address",
|
||||
"newpassword": "Password",
|
||||
"newpasswordretype": "Usba ang password",
|
||||
"showinsearch": "Ipakita sa user search",
|
||||
"changeaction": "Usba ang datos sa user",
|
||||
"oldpassword": "Karaan nga password (gikinahanglan)",
|
||||
"validation": {
|
||||
"newPasswordTooShort": "Ang bag-ong password kinahanglan adunay labing menos 8 ka karakter.",
|
||||
"passwordMismatch": "Dili magkapareho ang mga password.",
|
||||
"oldPasswordRequired": "Aron mausab ang password, gikinahanglan ang karon nga password."
|
||||
},
|
||||
"feedback": {
|
||||
"saved": "Malampuson nga nasave ang account settings.",
|
||||
"saveError": "Adunay sayop sa pagsave sa account settings."
|
||||
}
|
||||
},
|
||||
"flirt": {
|
||||
"title": "Flirt"
|
||||
},
|
||||
"interests": {
|
||||
"title": "Mga interes",
|
||||
"new": "Bag-ong interes",
|
||||
"add": "Idugang"
|
||||
},
|
||||
"feedback": {
|
||||
"updateError": "Dili masave ang kausaban.",
|
||||
"visibilityUpdateError": "Dili ma-update ang visibility."
|
||||
}
|
||||
}
|
||||
}
|
||||
196
frontend/src/i18n/locales/ceb/socialnetwork.json
Normal file
196
frontend/src/i18n/locales/ceb/socialnetwork.json
Normal file
@@ -0,0 +1,196 @@
|
||||
{
|
||||
"socialnetwork": {
|
||||
"usersearch": {
|
||||
"title": "Pagpangita og user",
|
||||
"username": "Username",
|
||||
"age_from": "Edad gikan sa",
|
||||
"age_to": "hangtod",
|
||||
"gender": "Gender",
|
||||
"search_button": "Pangita",
|
||||
"no_results": "Walay nakit-an nga resulta",
|
||||
"results_title": "Mga resulta sa pagpangita:",
|
||||
"result": {
|
||||
"nick": "Nickname",
|
||||
"gender": "Gender",
|
||||
"age": "Edad"
|
||||
}
|
||||
},
|
||||
"profile": {
|
||||
"pretitle": "Nag-load sa datos. Palihog hulat...",
|
||||
"error_title": "Wala makit-i ang user",
|
||||
"title": "Profile ni <username>",
|
||||
"tab": {
|
||||
"general": "Kinatibuk-an",
|
||||
"sexuality": "Sekswalidad",
|
||||
"images": "Gallery",
|
||||
"guestbook": "Guestbook"
|
||||
},
|
||||
"values": {
|
||||
"bool": {
|
||||
"true": "Oo",
|
||||
"false": "Dili"
|
||||
},
|
||||
"smokes": {
|
||||
"never": "Wala gayud",
|
||||
"socially": "Kung kauban",
|
||||
"often": "Kanunay",
|
||||
"daily": "Adlaw-adlaw"
|
||||
},
|
||||
"drinks": {
|
||||
"never": "Wala gayud",
|
||||
"socially": "Kung kauban",
|
||||
"often": "Kanunay",
|
||||
"daily": "Adlaw-adlaw"
|
||||
},
|
||||
"interestedInGender": {
|
||||
"male": "Lalaki",
|
||||
"female": "Babaye"
|
||||
},
|
||||
"sexualpreference": {
|
||||
"straight": "Heterosexual",
|
||||
"gay": "Homosexual",
|
||||
"bi": "Bisexual",
|
||||
"pan": "Pansexual",
|
||||
"asexual": "Asexual"
|
||||
},
|
||||
"gender": {
|
||||
"male": "Lalaki",
|
||||
"female": "Babaye",
|
||||
"transmale": "Trans-Female",
|
||||
"transfemale": "Trans-Male",
|
||||
"nonbinary": "Non-binary"
|
||||
},
|
||||
"language": {
|
||||
"de": "Aleman",
|
||||
"en": "Iningles",
|
||||
"ceb": "Bisaya"
|
||||
}
|
||||
},
|
||||
"guestbook": {
|
||||
"showInput": "Ipakita ang bag-ong entry",
|
||||
"hideInput": "Tagoa ang bag-ong entry",
|
||||
"imageUpload": "Hulagway",
|
||||
"submit": "Ipadala ang entry",
|
||||
"noEntries": "Walay entry nga nakit-an"
|
||||
},
|
||||
"interestedInGender": "Interesado sa",
|
||||
"hasChildren": "Naay mga anak",
|
||||
"smokes": "Pagpanigarilyo",
|
||||
"drinks": "Alak",
|
||||
"willChildren": "Gusto og anak",
|
||||
"sexualpreference": "Sekswal nga oryentasyon",
|
||||
"language": "Pinulongan",
|
||||
"gender": "Gender",
|
||||
"birthdate": "Petsa sa pagkatawo",
|
||||
"age": "Edad",
|
||||
"town": "Lungsod",
|
||||
"bodyheight": "Gitas-on",
|
||||
"weight": "Timbang"
|
||||
},
|
||||
"gallery": {
|
||||
"title": "Gallery",
|
||||
"folders": "Mga folder",
|
||||
"create_folder": "Paghimo og folder",
|
||||
"upload": {
|
||||
"title": "I-upload ang hulagway",
|
||||
"image_title": "Pamagat",
|
||||
"image_file": "File",
|
||||
"visibility": "Makita sa",
|
||||
"upload_button": "I-upload",
|
||||
"selectvisibility": "Palihog pagpili"
|
||||
},
|
||||
"images": "Mga hulagway",
|
||||
"visibility": {
|
||||
"everyone": "Tanan",
|
||||
"friends": "Mga higala",
|
||||
"adults": "Mga hamtong",
|
||||
"friends-and-adults": "Mga higala ug mga hamtong",
|
||||
"selected-users": "Piniling mga user",
|
||||
"none": "Wala"
|
||||
},
|
||||
"create_folder_dialog": {
|
||||
"title": "Paghimo og folder",
|
||||
"parent_folder": "Pagabuhaton sulod sa",
|
||||
"folder_title": "Ngalan sa folder",
|
||||
"visibility": "Makita sa",
|
||||
"select_visibility": "Palihog pagpili"
|
||||
},
|
||||
"noimages": "Wala pay mga hulagway niining foldera",
|
||||
"imagedialog": {
|
||||
"image_title": "Pamagat",
|
||||
"edit_visibility": "Makita sa",
|
||||
"save_changes": "I-save ang mga kausaban",
|
||||
"close": "Isira",
|
||||
"edit_visibility_placeholder": "Palihog pagpili"
|
||||
},
|
||||
"delete_folder_confirmation_title": "Tangtanga ang folder",
|
||||
"delete_folder_confirmation_message": "Tinuod ba nga gusto nimong tangtangon ang folder nga '%%folderName%%'?",
|
||||
"edit_image_dialog": {
|
||||
"title": "Usba ang datos sa hulagway"
|
||||
},
|
||||
"show_image_dialog": {
|
||||
"title": "Hulagway"
|
||||
}
|
||||
},
|
||||
"guestbook": {
|
||||
"title": "Guestbook",
|
||||
"prevPage": "Balik",
|
||||
"nextPage": "Sunod",
|
||||
"page": "Panid"
|
||||
},
|
||||
"diary": {
|
||||
"title": "Diary",
|
||||
"noEntries": "Wala ka pay nahimong diary entries.",
|
||||
"newEntry": "Bag-ong diary entry",
|
||||
"editEntry": "Usba ang diary entry",
|
||||
"save": "I-save",
|
||||
"update": "I-update",
|
||||
"cancel": "I-cancel",
|
||||
"edit": "Usba",
|
||||
"delete": "Tangtanga",
|
||||
"confirmDelete": "Tinuod ba nga gusto nimong tangtangon ang entry?",
|
||||
"prevPage": "Balik",
|
||||
"nextPage": "Sunod",
|
||||
"page": "Panid"
|
||||
},
|
||||
"forum": {
|
||||
"title": "Forum",
|
||||
"showNewTopic": "Paghimo og bag-ong topic",
|
||||
"hideNewTopic": "I-cancel ang paghimo",
|
||||
"noTitles": "Walay topic nga available",
|
||||
"topic": "Topic",
|
||||
"createNewTopic": "Paghimo og topic",
|
||||
"createdBy": "Gihimo ni",
|
||||
"createdAt": "Gihimo sa",
|
||||
"reactions": "Reaksiyon",
|
||||
"lastReaction": "Kataposang reaksiyon ni",
|
||||
"createNewMesssage": "Ipadala ang tubag"
|
||||
},
|
||||
"friendship": {
|
||||
"error": {
|
||||
"alreadyexists": "Anaa na daan ang friendship request"
|
||||
},
|
||||
"state": {
|
||||
"none": "Dili pa higala",
|
||||
"waiting": "Napadala na ang friendship request pero wala pa natubag",
|
||||
"open": "Gihangyo ang friendship",
|
||||
"denied": "Gibalibaran ang friendship request",
|
||||
"withdrawn": "Gibawi ang friendship request",
|
||||
"accepted": "Mga higala"
|
||||
},
|
||||
"added": "Nagpadala ka og friendship request.",
|
||||
"withdrawn": "Gibawi nimo ang friendship request.",
|
||||
"denied": "Gibalibaran nimo ang friendship request.",
|
||||
"accepted": "Natukod na ang panaghigala."
|
||||
},
|
||||
"erotic": {
|
||||
"eyebrow": "Erotic",
|
||||
"accessTitle": "I-unlock ang erotic area",
|
||||
"accessIntro": "Ang mga hulagway, video ug mga chat area sa ulahi makita lang sa edad 18 pataas ug magkinahanglan usab og moderator approval.",
|
||||
"lockedShort": "Magamit ra kini nga area human sa moderator approval.",
|
||||
"requestVerification": "Mangayo og access",
|
||||
"requestSent": "Napadala na ang access request.",
|
||||
"requestError": "Wala mapadala ang access request."
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,56 @@
|
||||
"title": "Titel",
|
||||
"publish": "Veröffentlichen",
|
||||
"pickImage": "Bild auswählen",
|
||||
"uploadImage": "Bild hochladen"
|
||||
"uploadImage": "Bild hochladen",
|
||||
"list": {
|
||||
"eyebrow": "Community-Blogs",
|
||||
"title": "Blogs",
|
||||
"intro": "Artikel, Projektstände und persönliche Einblicke aus der YourPart-Community.",
|
||||
"create": "Neuen Blog erstellen",
|
||||
"loading": "Laden…",
|
||||
"empty": "Keine Blogs gefunden.",
|
||||
"by": "von",
|
||||
"unknownAuthor": "Unbekannt",
|
||||
"open": "Zum Blog",
|
||||
"fallbackExcerpt": "Öffentliche Einträge, Gedanken und Projektstände aus der Community."
|
||||
},
|
||||
"view": {
|
||||
"loading": "Laden…",
|
||||
"edit": "Bearbeiten",
|
||||
"entriesCount": "{count} Einträge",
|
||||
"empty": "Keine Einträge vorhanden.",
|
||||
"fallbackDescription": "Öffentlicher Community-Blog auf YourPart.",
|
||||
"notFoundTitle": "Blog nicht gefunden | YourPart",
|
||||
"notFoundDescription": "Der angeforderte Blog konnte nicht geladen werden."
|
||||
},
|
||||
"editor": {
|
||||
"createTitle": "Blog erstellen",
|
||||
"editTitle": "Blog bearbeiten",
|
||||
"description": "Beschreibung",
|
||||
"visibility": "Sichtbarkeit",
|
||||
"visibilityPublic": "Öffentlich",
|
||||
"visibilityLoggedIn": "Nur eingeloggte Nutzer",
|
||||
"ageRange": "Altersbereich",
|
||||
"gender": "Geschlecht",
|
||||
"genderMale": "Männlich",
|
||||
"genderFemale": "Weiblich",
|
||||
"save": "Speichern",
|
||||
"newPostTitle": "Neuer Beitrag",
|
||||
"addPost": "Beitrag hinzufügen",
|
||||
"shareTitle": "Blog teilen",
|
||||
"url": "URL",
|
||||
"copyLink": "Link kopieren",
|
||||
"shareToFriends": "An Freunde senden",
|
||||
"emailAddresses": "E-Mail-Adressen (Kommagetrennt)",
|
||||
"send": "Senden",
|
||||
"restrictedHint": "Hinweis: Dieser Blog ist nicht öffentlich. Empfänger benötigen ggf. ein Login und passende Alters/Geschlechts-Berechtigung.",
|
||||
"invalidAgeRange": "Ungültiger Altersbereich",
|
||||
"copySuccess": "Link kopiert",
|
||||
"copyError": "Kopieren fehlgeschlagen",
|
||||
"shareError": "Teilen fehlgeschlagen",
|
||||
"emailError": "E-Mail-Versand fehlgeschlagen",
|
||||
"friendsSent": "An {count} Freund(e) gesendet.",
|
||||
"emailsSent": "{count} E-Mail(s) versendet."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -122,6 +122,7 @@
|
||||
},
|
||||
"overview": {
|
||||
"title": "Falukant - Übersicht",
|
||||
"heroIntro": "Dein Stand in Wirtschaft, Familie und Besitz in einer verdichteten Übersicht.",
|
||||
"heirSelection": {
|
||||
"title": "Erben-Auswahl",
|
||||
"description": "Dein bisheriger Charakter ist nicht mehr verfügbar. Wähle einen Erben aus der Liste, um mit diesem weiterzuspielen.",
|
||||
@@ -171,6 +172,16 @@
|
||||
"two_of": "Mindestens zwei Statusbedingungen"
|
||||
}
|
||||
},
|
||||
"summary": {
|
||||
"certificateHint": "Bestimmt, welche Produktkategorien du derzeit herstellen darfst.",
|
||||
"branches": "Niederlassungen",
|
||||
"branchesHint": "Direkter Zugriff auf deine wichtigsten Geschäftsstandorte.",
|
||||
"productions": "Produktionen aktiv",
|
||||
"productionsHint": "Laufende Produktionen, die zeitnah Abschluss oder Kontrolle brauchen.",
|
||||
"stock": "Lagerpositionen",
|
||||
"stockHint": "Verdichteter Blick auf Warenbestand über alle Regionen.",
|
||||
"open": "Öffnen"
|
||||
},
|
||||
"productions": {
|
||||
"title": "Produktionen"
|
||||
},
|
||||
@@ -258,6 +269,8 @@
|
||||
},
|
||||
"branch": {
|
||||
"title": "Filiale",
|
||||
"heroEyebrow": "Niederlassung",
|
||||
"heroIntro": "Produktion, Lager, Verkauf und Transport in einer spielweltbezogenen Steuerfläche.",
|
||||
"debtorsPrison": {
|
||||
"branchLocked": "Im Schuldturm sind neue wirtschaftliche Schritte blockiert. Geschlossene oder gepfändete Standorte werden hier ebenfalls sichtbar.",
|
||||
"branchRisk": "Dein Kreditverzug gefährdet Niederlassungen, Fahrzeuge und Lagerbestände.",
|
||||
@@ -1321,6 +1334,10 @@
|
||||
"upcoming": "Anstehende Neuwahl-Positionen",
|
||||
"elections": "Wahlen"
|
||||
},
|
||||
"bookmarkCandidate": "Für diese Kandidatur vormerken",
|
||||
"voteError": "Fehler beim Abgeben der Stimme",
|
||||
"voteAllError": "Fehler beim Abgeben der Stimmen",
|
||||
"applyError": "Bewerbung konnte nicht eingereicht werden.",
|
||||
"current": {
|
||||
"office": "Amt",
|
||||
"region": "Region",
|
||||
|
||||
@@ -58,5 +58,71 @@
|
||||
"cancel": "Abbrechen",
|
||||
"yes": "Ja",
|
||||
"no": "Nein"
|
||||
},
|
||||
"sectionBar": {
|
||||
"sections": {
|
||||
"default": "Bereich",
|
||||
"falukant": "Falukant",
|
||||
"vocab": "Vokabeltrainer",
|
||||
"forum": "Forum",
|
||||
"community": "Community",
|
||||
"settings": "Einstellungen",
|
||||
"administration": "Administration",
|
||||
"minigames": "Minispiele",
|
||||
"personal": "Persönlich",
|
||||
"blog": "Blog"
|
||||
},
|
||||
"titles": {
|
||||
"friends": "Freunde",
|
||||
"guestbook": "Gästebuch",
|
||||
"search": "Suche",
|
||||
"gallery": "Galerie",
|
||||
"forum": "Forum",
|
||||
"topic": "Thema",
|
||||
"diary": "Tagebuch",
|
||||
"languages": "Sprachen",
|
||||
"newLanguage": "Neue Sprache",
|
||||
"subscribeLanguage": "Sprache abonnieren",
|
||||
"language": "Sprache",
|
||||
"chapter": "Kapitel",
|
||||
"courses": "Kurse",
|
||||
"course": "Kurs",
|
||||
"lesson": "Lektion",
|
||||
"createCharacter": "Charakter erstellen",
|
||||
"overview": "Übersicht",
|
||||
"branch": "Niederlassung",
|
||||
"moneyHistory": "Geldverlauf",
|
||||
"family": "Familie",
|
||||
"house": "Haus",
|
||||
"nobility": "Adel",
|
||||
"reputation": "Ansehen",
|
||||
"church": "Kirche",
|
||||
"education": "Bildung",
|
||||
"bank": "Bank",
|
||||
"directors": "Direktoren",
|
||||
"health": "Gesundheit",
|
||||
"politics": "Politik",
|
||||
"underground": "Untergrund",
|
||||
"personalSettings": "Persönliche Daten",
|
||||
"viewSettings": "Ansicht",
|
||||
"sexualitySettings": "Sexualität",
|
||||
"flirtSettings": "Flirt",
|
||||
"accountSettings": "Account",
|
||||
"languageAssistantSettings": "Sprachassistent",
|
||||
"interests": "Interessen",
|
||||
"adminInterests": "Interessenverwaltung",
|
||||
"adminUsers": "Benutzer",
|
||||
"adminUserStatistics": "Benutzerstatistik",
|
||||
"adminContacts": "Kontaktanfragen",
|
||||
"adminUserRights": "Rechte",
|
||||
"adminForums": "Forumverwaltung",
|
||||
"adminChatRooms": "Chaträume",
|
||||
"adminFalukantUsers": "Falukant-Nutzer",
|
||||
"adminFalukantMap": "Falukant-Karte",
|
||||
"adminCreateNpc": "NPC erstellen",
|
||||
"adminMinigames": "Match3-Verwaltung",
|
||||
"adminTaxiTools": "Taxi-Tools",
|
||||
"adminServicesStatus": "Service-Status"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,13 @@
|
||||
"totalScore": "Gesamtpunktzahl",
|
||||
"totalStars": "Gesamtsterne",
|
||||
"levelsCompleted": "Abgeschlossene Level",
|
||||
"restartCampaign": "Kampagne neu starten"
|
||||
"restartCampaign": "Kampagne neu starten",
|
||||
"nextStep": "Nächster Schritt",
|
||||
"objectivesCollapse": "Ziele einklappen",
|
||||
"objectivesShow": "Ziele anzeigen",
|
||||
"objectives": "Ziele",
|
||||
"loadingBoard": "Spielbrett wird vorbereitet...",
|
||||
"loadingHint": "Leveldaten, Ziele und Feldlayout werden gerade synchronisiert."
|
||||
},
|
||||
"taxi": {
|
||||
"title": "Taxi Simulator",
|
||||
@@ -64,6 +70,34 @@
|
||||
"refuel": "Tanken",
|
||||
"startEngine": "Motor starten",
|
||||
"stopEngine": "Motor stoppen",
|
||||
"controls": "Steuerung",
|
||||
"accelerate": "Gas geben",
|
||||
"brake": "Bremsen",
|
||||
"steerRight": "Rechts lenken",
|
||||
"steerLeft": "Links lenken",
|
||||
"goals": "Ziele",
|
||||
"avoidCollisions": "Vermeide Kollisionen mit anderen Fahrzeugen",
|
||||
"streetNames": "Straßennamen",
|
||||
"remainingVehicles": "Verbleibende Fahrzeuge",
|
||||
"fuelTitle": "Treibstoff",
|
||||
"pointsTitle": "Punkte",
|
||||
"speedViolations": "Geschwindigkeitsverstöße",
|
||||
"redLightsPassed": "Rote Ampeln überfahren",
|
||||
"highscore": "Highscore",
|
||||
"topPlayers": "Top 20 Spieler",
|
||||
"loadingHighscore": "Lade Highscore...",
|
||||
"noHighscore": "Noch keine Highscores vorhanden",
|
||||
"pointsShort": "Pkt",
|
||||
"backToGame": "Zurück zum Spiel",
|
||||
"minimap": "Minimap",
|
||||
"loadedPassengers": "Geladene Passagiere",
|
||||
"waitingPassengers": "Wartende Passagiere",
|
||||
"noPassengersInTaxi": "Keine Passagiere im Taxi",
|
||||
"noWaitingPassengers": "Keine wartenden Passagiere",
|
||||
"name": "Name",
|
||||
"destination": "Ziel",
|
||||
"bonus": "Bonus",
|
||||
"time": "Zeit",
|
||||
"crash": {
|
||||
"title": "Unfall!",
|
||||
"message": "Du hattest einen Unfall! Crashes: {crashes}"
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
"email": "E-Mail",
|
||||
"reset": "Zurücksetzen",
|
||||
"success": "Falls die E-Mail existiert, wurde eine Anleitung zum Zurücksetzen gesendet.",
|
||||
"failure": "Passwort-Zurücksetzen fehlgeschlagen. Bitte später erneut versuchen."
|
||||
"failure": "Passwort-Zurücksetzen fehlgeschlagen. Bitte später erneut versuchen.",
|
||||
"emailHint": "Wir senden den Link an die hinterlegte E-Mail-Adresse.",
|
||||
"validation": {
|
||||
"invalidEmail": "Bitte eine gültige E-Mail-Adresse eingeben."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
"language": "Sprache",
|
||||
"languages": {
|
||||
"en": "Englisch",
|
||||
"de": "Deutsch"
|
||||
"de": "Deutsch",
|
||||
"ceb": "Bisaya"
|
||||
},
|
||||
"register": "Registrieren",
|
||||
"close": "Schließen",
|
||||
@@ -16,6 +17,12 @@
|
||||
"success": "Du wurdest erfolgreich registriert. Bitte schaue jetzt in Dein E-Mail-Postfach zum Aktivieren Deines Zugangs.",
|
||||
"passwordMismatch": "Die Passwörter stimmen nicht überein.",
|
||||
"emailinuse": "Die E-Mail-Adresse wird bereits verwendet.",
|
||||
"usernameinuse": "Der Benutzername ist nicht verfügbar."
|
||||
"usernameinuse": "Der Benutzername ist nicht verfügbar.",
|
||||
"validation": {
|
||||
"invalidEmail": "Bitte eine gültige E-Mail-Adresse eingeben.",
|
||||
"usernameTooShort": "Der Benutzername sollte mindestens 3 Zeichen haben.",
|
||||
"passwordHint": "Mindestens 8 Zeichen.",
|
||||
"passwordTooShort": "Das Passwort ist noch zu kurz."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,8 @@
|
||||
},
|
||||
"language": {
|
||||
"de": "Deutsch",
|
||||
"en": "Englisch"
|
||||
"en": "Englisch",
|
||||
"ceb": "Bisaya"
|
||||
},
|
||||
"eyecolor": {
|
||||
"blue": "Blau",
|
||||
@@ -140,6 +141,8 @@
|
||||
},
|
||||
"account": {
|
||||
"title": "Account",
|
||||
"heroEyebrow": "Einstellungen",
|
||||
"heroIntro": "Benutzername, E-Mail, Passwort und Sichtbarkeit an einer Stelle pflegen.",
|
||||
"username": "Benutzername",
|
||||
"email": "E-Mail-Adresse",
|
||||
"newpassword": "Passwort",
|
||||
@@ -149,6 +152,15 @@
|
||||
"showinsearch": "In Usersuchen anzeigen",
|
||||
"changeaction": "Benutzerdaten ändern",
|
||||
"oldpassword": "Altes Passwort (benötigt)",
|
||||
"validation": {
|
||||
"newPasswordTooShort": "Das neue Passwort sollte mindestens 8 Zeichen haben.",
|
||||
"passwordMismatch": "Die Passwörter stimmen nicht überein.",
|
||||
"oldPasswordRequired": "Zum Passwortwechsel wird das aktuelle Passwort benötigt."
|
||||
},
|
||||
"feedback": {
|
||||
"saved": "Account-Einstellungen erfolgreich gespeichert.",
|
||||
"saveError": "Ein Fehler ist beim Speichern der Account-Einstellungen aufgetreten."
|
||||
},
|
||||
"adultAccessTitle": "Erotikbereich",
|
||||
"adultAccessIntro": "Der Erotikbereich ist nur für volljährige Nutzer gedacht und wird zusätzlich durch Moderatoren freigeschaltet.",
|
||||
"requestAdultVerification": "Freischaltung anfragen",
|
||||
@@ -216,6 +228,10 @@
|
||||
"AdultsOnly": "Nur Erwachsenen anzeigen",
|
||||
"All": "Jedem zeigen"
|
||||
},
|
||||
"feedback": {
|
||||
"updateError": "Änderung konnte nicht gespeichert werden.",
|
||||
"visibilityUpdateError": "Sichtbarkeit konnte nicht aktualisiert werden."
|
||||
},
|
||||
"flirt": {
|
||||
"title": "Flirt"
|
||||
},
|
||||
|
||||
@@ -6,6 +6,56 @@
|
||||
"title": "Title",
|
||||
"publish": "Publish",
|
||||
"pickImage": "Pick an image",
|
||||
"uploadImage": "Upload image"
|
||||
"uploadImage": "Upload image",
|
||||
"list": {
|
||||
"eyebrow": "Community blogs",
|
||||
"title": "Blogs",
|
||||
"intro": "Articles, project updates and personal insights from the YourPart community.",
|
||||
"create": "Create new blog",
|
||||
"loading": "Loading…",
|
||||
"empty": "No blogs found.",
|
||||
"by": "by",
|
||||
"unknownAuthor": "Unknown",
|
||||
"open": "Open blog",
|
||||
"fallbackExcerpt": "Public entries, thoughts and project updates from the community."
|
||||
},
|
||||
"view": {
|
||||
"loading": "Loading…",
|
||||
"edit": "Edit",
|
||||
"entriesCount": "{count} entries",
|
||||
"empty": "No entries available.",
|
||||
"fallbackDescription": "Public community blog on YourPart.",
|
||||
"notFoundTitle": "Blog not found | YourPart",
|
||||
"notFoundDescription": "The requested blog could not be loaded."
|
||||
},
|
||||
"editor": {
|
||||
"createTitle": "Create blog",
|
||||
"editTitle": "Edit blog",
|
||||
"description": "Description",
|
||||
"visibility": "Visibility",
|
||||
"visibilityPublic": "Public",
|
||||
"visibilityLoggedIn": "Logged-in users only",
|
||||
"ageRange": "Age range",
|
||||
"gender": "Gender",
|
||||
"genderMale": "Male",
|
||||
"genderFemale": "Female",
|
||||
"save": "Save",
|
||||
"newPostTitle": "New post",
|
||||
"addPost": "Add post",
|
||||
"shareTitle": "Share blog",
|
||||
"url": "URL",
|
||||
"copyLink": "Copy link",
|
||||
"shareToFriends": "Send to friends",
|
||||
"emailAddresses": "Email addresses (comma-separated)",
|
||||
"send": "Send",
|
||||
"restrictedHint": "Note: This blog is not public. Recipients may need a login and matching age/gender permissions.",
|
||||
"invalidAgeRange": "Invalid age range",
|
||||
"copySuccess": "Link copied",
|
||||
"copyError": "Copy failed",
|
||||
"shareError": "Sharing failed",
|
||||
"emailError": "Email sending failed",
|
||||
"friendsSent": "Sent to {count} friend(s).",
|
||||
"emailsSent": "{count} email(s) sent."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,6 +103,7 @@
|
||||
},
|
||||
"overview": {
|
||||
"title": "Falukant - Overview",
|
||||
"heroIntro": "Your status in economy, family and property in a condensed overview.",
|
||||
"heirSelection": {
|
||||
"title": "Heir Selection",
|
||||
"description": "Your previous character is no longer available. Choose an heir from the list to continue playing.",
|
||||
@@ -151,6 +152,16 @@
|
||||
"one_of": "At least one status condition",
|
||||
"two_of": "At least two status conditions"
|
||||
}
|
||||
},
|
||||
"summary": {
|
||||
"certificateHint": "Determines which product categories you may currently produce.",
|
||||
"branches": "Branches",
|
||||
"branchesHint": "Direct access to your most important business locations.",
|
||||
"productions": "Active productions",
|
||||
"productionsHint": "Ongoing productions that will soon need completion or review.",
|
||||
"stock": "Storage positions",
|
||||
"stockHint": "Condensed view of goods across all regions.",
|
||||
"open": "Open"
|
||||
}
|
||||
},
|
||||
"health": {
|
||||
@@ -312,6 +323,9 @@
|
||||
"noProposals": "No director candidates available."
|
||||
},
|
||||
"branch": {
|
||||
"title": "Branch",
|
||||
"heroEyebrow": "Branch",
|
||||
"heroIntro": "Production, storage, sales and transport in one world-related control area.",
|
||||
"debtorsPrison": {
|
||||
"branchLocked": "While in debtors' prison, new economic steps are blocked. Closed or seized branches will also become visible here.",
|
||||
"branchRisk": "Your delinquency puts branches, vehicles and stored goods at risk.",
|
||||
@@ -539,6 +553,10 @@
|
||||
"upcoming": "Upcoming Positions",
|
||||
"elections": "Elections"
|
||||
},
|
||||
"bookmarkCandidate": "Bookmark this candidacy",
|
||||
"voteError": "Error while submitting the vote",
|
||||
"voteAllError": "Error while submitting the votes",
|
||||
"applyError": "Application could not be submitted.",
|
||||
"current": {
|
||||
"office": "Office",
|
||||
"region": "Region",
|
||||
|
||||
@@ -58,5 +58,71 @@
|
||||
"cancel": "Cancel",
|
||||
"yes": "Yes",
|
||||
"no": "No"
|
||||
},
|
||||
"sectionBar": {
|
||||
"sections": {
|
||||
"default": "Section",
|
||||
"falukant": "Falukant",
|
||||
"vocab": "Vocabulary trainer",
|
||||
"forum": "Forum",
|
||||
"community": "Community",
|
||||
"settings": "Settings",
|
||||
"administration": "Administration",
|
||||
"minigames": "Minigames",
|
||||
"personal": "Personal",
|
||||
"blog": "Blog"
|
||||
},
|
||||
"titles": {
|
||||
"friends": "Friends",
|
||||
"guestbook": "Guestbook",
|
||||
"search": "Search",
|
||||
"gallery": "Gallery",
|
||||
"forum": "Forum",
|
||||
"topic": "Topic",
|
||||
"diary": "Diary",
|
||||
"languages": "Languages",
|
||||
"newLanguage": "New language",
|
||||
"subscribeLanguage": "Subscribe to language",
|
||||
"language": "Language",
|
||||
"chapter": "Chapter",
|
||||
"courses": "Courses",
|
||||
"course": "Course",
|
||||
"lesson": "Lesson",
|
||||
"createCharacter": "Create character",
|
||||
"overview": "Overview",
|
||||
"branch": "Branch",
|
||||
"moneyHistory": "Money history",
|
||||
"family": "Family",
|
||||
"house": "House",
|
||||
"nobility": "Nobility",
|
||||
"reputation": "Reputation",
|
||||
"church": "Church",
|
||||
"education": "Education",
|
||||
"bank": "Bank",
|
||||
"directors": "Directors",
|
||||
"health": "Health",
|
||||
"politics": "Politics",
|
||||
"underground": "Underground",
|
||||
"personalSettings": "Personal data",
|
||||
"viewSettings": "View",
|
||||
"sexualitySettings": "Sexuality",
|
||||
"flirtSettings": "Flirt",
|
||||
"accountSettings": "Account",
|
||||
"languageAssistantSettings": "Language assistant",
|
||||
"interests": "Interests",
|
||||
"adminInterests": "Interest administration",
|
||||
"adminUsers": "Users",
|
||||
"adminUserStatistics": "User statistics",
|
||||
"adminContacts": "Contact requests",
|
||||
"adminUserRights": "Rights",
|
||||
"adminForums": "Forum administration",
|
||||
"adminChatRooms": "Chat rooms",
|
||||
"adminFalukantUsers": "Falukant users",
|
||||
"adminFalukantMap": "Falukant map",
|
||||
"adminCreateNpc": "Create NPC",
|
||||
"adminMinigames": "Match3 administration",
|
||||
"adminTaxiTools": "Taxi tools",
|
||||
"adminServicesStatus": "Service status"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,13 @@
|
||||
"totalScore": "Total Score",
|
||||
"totalStars": "Total Stars",
|
||||
"levelsCompleted": "Levels Completed",
|
||||
"restartCampaign": "Restart Campaign"
|
||||
"restartCampaign": "Restart Campaign",
|
||||
"nextStep": "Next step",
|
||||
"objectivesCollapse": "Collapse objectives",
|
||||
"objectivesShow": "Show objectives",
|
||||
"objectives": "Objectives",
|
||||
"loadingBoard": "Preparing game board...",
|
||||
"loadingHint": "Level data, objectives and board layout are being synchronized."
|
||||
},
|
||||
"taxi": {
|
||||
"title": "Taxi Simulator",
|
||||
@@ -64,6 +70,34 @@
|
||||
"refuel": "Refuel",
|
||||
"startEngine": "Start Engine",
|
||||
"stopEngine": "Stop Engine",
|
||||
"controls": "Controls",
|
||||
"accelerate": "Accelerate",
|
||||
"brake": "Brake",
|
||||
"steerRight": "Steer right",
|
||||
"steerLeft": "Steer left",
|
||||
"goals": "Goals",
|
||||
"avoidCollisions": "Avoid collisions with other vehicles",
|
||||
"streetNames": "Street names",
|
||||
"remainingVehicles": "Remaining vehicles",
|
||||
"fuelTitle": "Fuel",
|
||||
"pointsTitle": "Points",
|
||||
"speedViolations": "Speed violations",
|
||||
"redLightsPassed": "Red lights crossed",
|
||||
"highscore": "Highscore",
|
||||
"topPlayers": "Top 20 players",
|
||||
"loadingHighscore": "Loading highscore...",
|
||||
"noHighscore": "No highscores yet",
|
||||
"pointsShort": "pts",
|
||||
"backToGame": "Back to game",
|
||||
"minimap": "Minimap",
|
||||
"loadedPassengers": "Loaded passengers",
|
||||
"waitingPassengers": "Waiting passengers",
|
||||
"noPassengersInTaxi": "No passengers in the taxi",
|
||||
"noWaitingPassengers": "No waiting passengers",
|
||||
"name": "Name",
|
||||
"destination": "Destination",
|
||||
"bonus": "Bonus",
|
||||
"time": "Time",
|
||||
"crash": {
|
||||
"title": "Crash!",
|
||||
"message": "You had an accident! Crashes: {crashes}"
|
||||
|
||||
@@ -4,6 +4,10 @@
|
||||
"email": "Email",
|
||||
"reset": "Reset",
|
||||
"success": "If the email exists, we've sent reset instructions.",
|
||||
"failure": "Password reset failed. Please try again later."
|
||||
"failure": "Password reset failed. Please try again later.",
|
||||
"emailHint": "We send the link to the stored email address.",
|
||||
"validation": {
|
||||
"invalidEmail": "Please enter a valid email address."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,7 +8,8 @@
|
||||
"language": "Language",
|
||||
"languages": {
|
||||
"en": "English",
|
||||
"de": "German"
|
||||
"de": "German",
|
||||
"ceb": "Bisaya"
|
||||
},
|
||||
"register": "Register",
|
||||
"close": "Close",
|
||||
@@ -16,6 +17,12 @@
|
||||
"success": "You have been successfully registered. Please check your email to activate your account.",
|
||||
"passwordMismatch": "The passwords do not match.",
|
||||
"emailinuse": "The email address is already in use.",
|
||||
"usernameinuse": "The username is not available."
|
||||
"usernameinuse": "The username is not available.",
|
||||
"validation": {
|
||||
"invalidEmail": "Please enter a valid email address.",
|
||||
"usernameTooShort": "The username should have at least 3 characters.",
|
||||
"passwordHint": "At least 8 characters.",
|
||||
"passwordTooShort": "The password is still too short."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,8 @@
|
||||
},
|
||||
"language": {
|
||||
"de": "German",
|
||||
"en": "English"
|
||||
"en": "English",
|
||||
"ceb": "Bisaya"
|
||||
},
|
||||
"eyecolor": {
|
||||
"blue": "Blue",
|
||||
@@ -140,6 +141,8 @@
|
||||
},
|
||||
"account": {
|
||||
"title": "Account",
|
||||
"heroEyebrow": "Settings",
|
||||
"heroIntro": "Manage username, email, password and visibility in one place.",
|
||||
"username": "Username",
|
||||
"email": "Email Address",
|
||||
"newpassword": "Password",
|
||||
@@ -149,6 +152,15 @@
|
||||
"showinsearch": "Show in User Search",
|
||||
"changeaction": "Change User Data",
|
||||
"oldpassword": "Old Password (required)",
|
||||
"validation": {
|
||||
"newPasswordTooShort": "The new password should have at least 8 characters.",
|
||||
"passwordMismatch": "The passwords do not match.",
|
||||
"oldPasswordRequired": "To change the password, the current password is required."
|
||||
},
|
||||
"feedback": {
|
||||
"saved": "Account settings saved successfully.",
|
||||
"saveError": "An error occurred while saving the account settings."
|
||||
},
|
||||
"adultAccessTitle": "Erotic area",
|
||||
"adultAccessIntro": "The erotic area is intended only for adult users and also requires moderator approval.",
|
||||
"requestAdultVerification": "Request access",
|
||||
@@ -216,6 +228,10 @@
|
||||
"AdultsOnly": "Show only to adults",
|
||||
"All": "Show to everyone"
|
||||
},
|
||||
"feedback": {
|
||||
"updateError": "The change could not be saved.",
|
||||
"visibilityUpdateError": "The visibility could not be updated."
|
||||
},
|
||||
"flirt": {
|
||||
"title": "Flirt"
|
||||
},
|
||||
|
||||
@@ -58,5 +58,71 @@
|
||||
"cancel": "Cancelar",
|
||||
"yes": "Sí",
|
||||
"no": "No"
|
||||
},
|
||||
"sectionBar": {
|
||||
"sections": {
|
||||
"default": "Sección",
|
||||
"falukant": "Falukant",
|
||||
"vocab": "Entrenador de vocabulario",
|
||||
"forum": "Foro",
|
||||
"community": "Comunidad",
|
||||
"settings": "Configuración",
|
||||
"administration": "Administración",
|
||||
"minigames": "Minijuegos",
|
||||
"personal": "Personal",
|
||||
"blog": "Blog"
|
||||
},
|
||||
"titles": {
|
||||
"friends": "Amigos",
|
||||
"guestbook": "Libro de visitas",
|
||||
"search": "Buscar",
|
||||
"gallery": "Galería",
|
||||
"forum": "Foro",
|
||||
"topic": "Tema",
|
||||
"diary": "Diario",
|
||||
"languages": "Idiomas",
|
||||
"newLanguage": "Nuevo idioma",
|
||||
"subscribeLanguage": "Suscribirse al idioma",
|
||||
"language": "Idioma",
|
||||
"chapter": "Capítulo",
|
||||
"courses": "Cursos",
|
||||
"course": "Curso",
|
||||
"lesson": "Lección",
|
||||
"createCharacter": "Crear personaje",
|
||||
"overview": "Resumen",
|
||||
"branch": "Sucursal",
|
||||
"moneyHistory": "Historial de dinero",
|
||||
"family": "Familia",
|
||||
"house": "Casa",
|
||||
"nobility": "Nobleza",
|
||||
"reputation": "Reputación",
|
||||
"church": "Iglesia",
|
||||
"education": "Educación",
|
||||
"bank": "Banco",
|
||||
"directors": "Directores",
|
||||
"health": "Salud",
|
||||
"politics": "Política",
|
||||
"underground": "Submundo",
|
||||
"personalSettings": "Datos personales",
|
||||
"viewSettings": "Vista",
|
||||
"sexualitySettings": "Sexualidad",
|
||||
"flirtSettings": "Coqueteo",
|
||||
"accountSettings": "Cuenta",
|
||||
"languageAssistantSettings": "Asistente de idiomas",
|
||||
"interests": "Intereses",
|
||||
"adminInterests": "Administración de intereses",
|
||||
"adminUsers": "Usuarios",
|
||||
"adminUserStatistics": "Estadísticas de usuarios",
|
||||
"adminContacts": "Solicitudes de contacto",
|
||||
"adminUserRights": "Permisos",
|
||||
"adminForums": "Administración del foro",
|
||||
"adminChatRooms": "Salas de chat",
|
||||
"adminFalukantUsers": "Usuarios de Falukant",
|
||||
"adminFalukantMap": "Mapa de Falukant",
|
||||
"adminCreateNpc": "Crear NPC",
|
||||
"adminMinigames": "Administración de Match3",
|
||||
"adminTaxiTools": "Herramientas de taxi",
|
||||
"adminServicesStatus": "Estado del servicio"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,8 @@
|
||||
},
|
||||
"language": {
|
||||
"de": "Alemán",
|
||||
"en": "Inglés"
|
||||
"en": "Inglés",
|
||||
"ceb": "Bisaya"
|
||||
},
|
||||
"eyecolor": {
|
||||
"blue": "Azul",
|
||||
|
||||
@@ -12,6 +12,10 @@ import feedbackPlugin from './utils/feedback';
|
||||
function getBrowserLanguage() {
|
||||
// Prüfe zuerst die bevorzugte Sprache
|
||||
const browserLanguage = navigator.language || navigator.languages[0];
|
||||
|
||||
if (browserLanguage.startsWith('ceb') || browserLanguage.startsWith('bis')) {
|
||||
return 'ceb';
|
||||
}
|
||||
|
||||
// Deutschsprachige Länder: Deutschland, Österreich, Schweiz, Liechtenstein
|
||||
const germanSpeakingCountries = ['de', 'at', 'ch', 'li'];
|
||||
@@ -24,6 +28,9 @@ function getBrowserLanguage() {
|
||||
// Prüfe alle verfügbaren Sprachen für deutschsprachige Länder
|
||||
const allLanguages = navigator.languages || [navigator.language];
|
||||
for (const lang of allLanguages) {
|
||||
if (lang.startsWith('ceb') || lang.startsWith('bis')) {
|
||||
return 'ceb';
|
||||
}
|
||||
// Prüfe auf de-XX Format (z.B. de-DE, de-AT, de-CH, de-LI)
|
||||
if (lang.startsWith('de-')) {
|
||||
const countryCode = lang.split('-')[1]?.toLowerCase();
|
||||
|
||||
@@ -54,6 +54,11 @@ const store = createStore({
|
||||
language: (() => {
|
||||
// Verwende die gleiche Logik wie in main.js
|
||||
const browserLanguage = navigator.language || navigator.languages[0];
|
||||
|
||||
if (browserLanguage.startsWith('ceb') || browserLanguage.startsWith('bis')) {
|
||||
return 'ceb';
|
||||
}
|
||||
|
||||
const germanSpeakingCountries = ['de', 'at', 'ch', 'li'];
|
||||
|
||||
if (browserLanguage.startsWith('de')) {
|
||||
@@ -62,6 +67,9 @@ const store = createStore({
|
||||
|
||||
const allLanguages = navigator.languages || [navigator.language];
|
||||
for (const lang of allLanguages) {
|
||||
if (lang.startsWith('ceb') || lang.startsWith('bis')) {
|
||||
return 'ceb';
|
||||
}
|
||||
if (lang.startsWith('de-')) {
|
||||
const countryCode = lang.split('-')[1]?.toLowerCase();
|
||||
if (germanSpeakingCountries.includes(countryCode)) {
|
||||
@@ -104,6 +112,12 @@ const store = createStore({
|
||||
|
||||
// Setze die Sprache auf die Browser-Sprache zurück
|
||||
const browserLanguage = navigator.language || navigator.languages[0];
|
||||
|
||||
if (browserLanguage.startsWith('ceb') || browserLanguage.startsWith('bis')) {
|
||||
state.language = 'ceb';
|
||||
return;
|
||||
}
|
||||
|
||||
const germanSpeakingCountries = ['de', 'at', 'ch', 'li'];
|
||||
|
||||
if (browserLanguage.startsWith('de')) {
|
||||
@@ -112,6 +126,10 @@ const store = createStore({
|
||||
const allLanguages = navigator.languages || [navigator.language];
|
||||
let isGerman = false;
|
||||
for (const lang of allLanguages) {
|
||||
if (lang.startsWith('ceb') || lang.startsWith('bis')) {
|
||||
state.language = 'ceb';
|
||||
return;
|
||||
}
|
||||
if (lang.startsWith('de-')) {
|
||||
const countryCode = lang.split('-')[1]?.toLowerCase();
|
||||
if (germanSpeakingCountries.includes(countryCode)) {
|
||||
|
||||
@@ -1,61 +1,61 @@
|
||||
<template>
|
||||
<div class="blog-editor">
|
||||
<h1>{{ isEdit ? 'Blog bearbeiten' : 'Blog erstellen' }}</h1>
|
||||
<h1>{{ isEdit ? $t('blog.editor.editTitle') : $t('blog.editor.createTitle') }}</h1>
|
||||
<form @submit.prevent="save">
|
||||
<div>
|
||||
<label>Titel</label>
|
||||
<label>{{ $t('blog.title') }}</label>
|
||||
<input v-model="form.title" required />
|
||||
</div>
|
||||
<div>
|
||||
<label>Beschreibung</label>
|
||||
<label>{{ $t('blog.editor.description') }}</label>
|
||||
<textarea v-model="form.description"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<label>Sichtbarkeit</label>
|
||||
<label>{{ $t('blog.editor.visibility') }}</label>
|
||||
<select v-model="form.visibility">
|
||||
<option value="public">Öffentlich</option>
|
||||
<option value="logged_in">Nur eingeloggte Nutzer</option>
|
||||
<option value="public">{{ $t('blog.editor.visibilityPublic') }}</option>
|
||||
<option value="logged_in">{{ $t('blog.editor.visibilityLoggedIn') }}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div v-if="form.visibility === 'logged_in'">
|
||||
<label>Altersbereich</label>
|
||||
<label>{{ $t('blog.editor.ageRange') }}</label>
|
||||
<div class="row">
|
||||
<input type="number" min="0" v-model.number="form.ageMin" placeholder="min" />
|
||||
<input type="number" min="0" v-model.number="form.ageMax" placeholder="max" />
|
||||
</div>
|
||||
<label>Geschlecht</label>
|
||||
<label>{{ $t('blog.editor.gender') }}</label>
|
||||
<div class="row">
|
||||
<label><input type="checkbox" value="m" v-model="genderSel"> Männlich</label>
|
||||
<label><input type="checkbox" value="f" v-model="genderSel"> Weiblich</label>
|
||||
<label><input type="checkbox" value="m" v-model="genderSel"> {{ $t('blog.editor.genderMale') }}</label>
|
||||
<label><input type="checkbox" value="f" v-model="genderSel"> {{ $t('blog.editor.genderFemale') }}</label>
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn" type="submit">Speichern</button>
|
||||
<button class="btn" type="submit">{{ $t('blog.editor.save') }}</button>
|
||||
</form>
|
||||
|
||||
<div v-if="isEdit" class="post-editor">
|
||||
<h2>Neuer Beitrag</h2>
|
||||
<h2>{{ $t('blog.editor.newPostTitle') }}</h2>
|
||||
<form @submit.prevent="addPost">
|
||||
<input v-model="post.title" placeholder="Titel" required />
|
||||
<input v-model="post.title" :placeholder="$t('blog.title')" required />
|
||||
<RichTextEditor v-model="post.content" :blog-id="$route.params.id" />
|
||||
<button class="btn" type="submit">Beitrag hinzufügen</button>
|
||||
<button class="btn" type="submit">{{ $t('blog.editor.addPost') }}</button>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div v-if="isEdit" class="share-section">
|
||||
<h2>Blog teilen</h2>
|
||||
<h2>{{ $t('blog.editor.shareTitle') }}</h2>
|
||||
<div class="share-url">
|
||||
<label>URL</label>
|
||||
<label>{{ $t('blog.editor.url') }}</label>
|
||||
<input :value="currentShareUrl" readonly @focus="$event.target.select()" />
|
||||
<button class="btn" type="button" @click="copyUrl">Link kopieren</button>
|
||||
<button class="btn" type="button" @click="copyUrl">{{ $t('blog.editor.copyLink') }}</button>
|
||||
</div>
|
||||
<div class="share-actions">
|
||||
<button class="btn" type="button" @click="shareToFriends">An Freunde senden</button>
|
||||
<button class="btn" type="button" @click="shareToFriends">{{ $t('blog.editor.shareToFriends') }}</button>
|
||||
</div>
|
||||
<div class="share-email">
|
||||
<label>E-Mail-Adressen (Kommagetrennt)</label>
|
||||
<label>{{ $t('blog.editor.emailAddresses') }}</label>
|
||||
<input v-model="emailInput" placeholder="name@example.com, second@example.org" />
|
||||
<button class="btn" type="button" @click="shareToEmails">Senden</button>
|
||||
<p v-if="form.visibility !== 'public'" class="hint">Hinweis: Dieser Blog ist nicht öffentlich. Empfänger benötigen ggf. ein Login und passende Alters/Geschlechts-Berechtigung.</p>
|
||||
<button class="btn" type="button" @click="shareToEmails">{{ $t('blog.editor.send') }}</button>
|
||||
<p v-if="form.visibility !== 'public'" class="hint">{{ $t('blog.editor.restrictedHint') }}</p>
|
||||
</div>
|
||||
<p v-if="shareStatus" class="status">{{ shareStatus }}</p>
|
||||
</div>
|
||||
@@ -108,7 +108,7 @@ export default {
|
||||
async save() {
|
||||
if (this.form.visibility === 'logged_in') {
|
||||
if (this.form.ageMin != null && this.form.ageMax != null && this.form.ageMin > this.form.ageMax) {
|
||||
showError(this, 'Ungültiger Altersbereich');
|
||||
showError(this, 'tr:blog.editor.invalidAgeRange');
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -152,9 +152,9 @@ export default {
|
||||
const url = this.currentShareUrl || this.blogAbsoluteUrl();
|
||||
try {
|
||||
await navigator.clipboard.writeText(url);
|
||||
this.shareStatus = 'Link kopiert';
|
||||
this.shareStatus = this.$t('blog.editor.copySuccess');
|
||||
} catch {
|
||||
this.shareStatus = 'Kopieren fehlgeschlagen';
|
||||
this.shareStatus = this.$t('blog.editor.copyError');
|
||||
}
|
||||
setTimeout(() => (this.shareStatus = ''), 2000);
|
||||
},
|
||||
@@ -162,9 +162,9 @@ export default {
|
||||
try {
|
||||
const res = await shareBlog(this.$route.params.id, { toFriends: true });
|
||||
if (res.url) this.currentShareUrl = res.url;
|
||||
this.shareStatus = `An ${res.notifiedFriends || 0} Freund(e) gesendet.`;
|
||||
this.shareStatus = this.$t('blog.editor.friendsSent', { count: res.notifiedFriends || 0 });
|
||||
} catch (e) {
|
||||
this.shareStatus = 'Teilen fehlgeschlagen';
|
||||
this.shareStatus = this.$t('blog.editor.shareError');
|
||||
}
|
||||
setTimeout(() => (this.shareStatus = ''), 3000);
|
||||
},
|
||||
@@ -174,9 +174,9 @@ export default {
|
||||
try {
|
||||
const res = await shareBlog(this.$route.params.id, { emails });
|
||||
if (res.url) this.currentShareUrl = res.url;
|
||||
this.shareStatus = `${res.emailsSent || 0} E-Mail(s) versendet.`;
|
||||
this.shareStatus = this.$t('blog.editor.emailsSent', { count: res.emailsSent || 0 });
|
||||
} catch (e) {
|
||||
this.shareStatus = 'E-Mail-Versand fehlgeschlagen';
|
||||
this.shareStatus = this.$t('blog.editor.emailError');
|
||||
}
|
||||
setTimeout(() => (this.shareStatus = ''), 3000);
|
||||
}
|
||||
|
||||
@@ -2,23 +2,23 @@
|
||||
<div class="blog-list">
|
||||
<section class="blog-list__hero surface-card">
|
||||
<div>
|
||||
<span class="blog-list__kicker">Community-Blogs</span>
|
||||
<h1>Blogs</h1>
|
||||
<p>Artikel, Projektstände und persönliche Einblicke aus der YourPart-Community.</p>
|
||||
<span class="blog-list__kicker">{{ $t('blog.list.eyebrow') }}</span>
|
||||
<h1>{{ $t('blog.list.title') }}</h1>
|
||||
<p>{{ $t('blog.list.intro') }}</p>
|
||||
</div>
|
||||
<div class="toolbar">
|
||||
<router-link v-if="$store.getters.isLoggedIn" class="btn" to="/blogs/create">Neuen Blog erstellen</router-link>
|
||||
<router-link v-if="$store.getters.isLoggedIn" class="btn" to="/blogs/create">{{ $t('blog.list.create') }}</router-link>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div v-if="loading" class="blog-list__state surface-card">Laden…</div>
|
||||
<div v-else-if="!blogs.length" class="blog-list__state surface-card">Keine Blogs gefunden.</div>
|
||||
<div v-if="loading" class="blog-list__state surface-card">{{ $t('blog.list.loading') }}</div>
|
||||
<div v-else-if="!blogs.length" class="blog-list__state surface-card">{{ $t('blog.list.empty') }}</div>
|
||||
<div v-else class="blog-grid">
|
||||
<article v-for="b in blogs" :key="b.id" class="blog-card surface-card">
|
||||
<div class="blog-card__meta">von {{ b.owner?.username || 'Unbekannt' }}</div>
|
||||
<div class="blog-card__meta">{{ $t('blog.list.by') }} {{ b.owner?.username || $t('blog.list.unknownAuthor') }}</div>
|
||||
<h2><router-link :to="blogUrl(b)">{{ b.title }}</router-link></h2>
|
||||
<p>{{ blogExcerpt(b) }}</p>
|
||||
<router-link class="blog-card__link" :to="blogUrl(b)">Zum Blog</router-link>
|
||||
<router-link class="blog-card__link" :to="blogUrl(b)">{{ $t('blog.list.open') }}</router-link>
|
||||
</article>
|
||||
</div>
|
||||
</div>
|
||||
@@ -39,7 +39,7 @@ export default {
|
||||
return slug ? `/blogs/${encodeURIComponent(slug)}` : `/blogs/${blog.id}`;
|
||||
},
|
||||
blogExcerpt(blog) {
|
||||
const source = blog?.description || 'Öffentliche Einträge, Gedanken und Projektstände aus der Community.';
|
||||
const source = blog?.description || this.$t('blog.list.fallbackExcerpt');
|
||||
return source.length > 150 ? `${source.slice(0, 147)}...` : source;
|
||||
},
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div class="blog-view">
|
||||
<div v-if="loading" class="blog-view__state surface-card">Laden…</div>
|
||||
<div v-if="loading" class="blog-view__state surface-card">{{ $t('blog.view.loading') }}</div>
|
||||
<div v-else-if="blog" class="blog-layout">
|
||||
<section class="blog-hero surface-card">
|
||||
<div>
|
||||
@@ -9,16 +9,16 @@
|
||||
<p v-if="blog.description" class="blog-description">{{ blog.description }}</p>
|
||||
</div>
|
||||
<div v-if="$store.getters.isLoggedIn" class="actions">
|
||||
<router-link class="editbutton" v-if="isOwner" :to="{ name: 'BlogEdit', params: { id: blog.id } }">Bearbeiten</router-link>
|
||||
<router-link class="editbutton" v-if="isOwner" :to="{ name: 'BlogEdit', params: { id: blog.id } }">{{ $t('blog.view.edit') }}</router-link>
|
||||
</div>
|
||||
</section>
|
||||
<div class="blog-content">
|
||||
<section class="posts surface-card">
|
||||
<div class="posts__header">
|
||||
<h2>{{ $t('blog.posts') }}</h2>
|
||||
<span class="posts__count">{{ total }} Einträge</span>
|
||||
<span class="posts__count">{{ $t('blog.view.entriesCount', { count: total }) }}</span>
|
||||
</div>
|
||||
<div v-if="!items.length" class="blog-view__state">Keine Einträge vorhanden.</div>
|
||||
<div v-if="!items.length" class="blog-view__state">{{ $t('blog.view.empty') }}</div>
|
||||
<article v-for="p in items" :key="p.id" class="post">
|
||||
<h3>{{ p.title }}</h3>
|
||||
<div class="content" v-html="sanitize(p.content)" />
|
||||
@@ -89,7 +89,7 @@ export default {
|
||||
.map((item) => `${item.title || ''} ${stripHtml(item.content || '')}`.trim())
|
||||
.filter(Boolean)
|
||||
.join(' ');
|
||||
const summarySource = this.blog.description || plainTextPosts || 'Öffentlicher Community-Blog auf YourPart.';
|
||||
const summarySource = this.blog.description || plainTextPosts || this.$t('blog.view.fallbackDescription');
|
||||
const description = truncateText(summarySource, 160);
|
||||
const canonicalPath = this.canonicalBlogPath();
|
||||
|
||||
@@ -146,8 +146,8 @@ export default {
|
||||
console.error('Blog konnte nicht geladen werden:', e);
|
||||
// this.$router.replace('/blogs');
|
||||
applySeo({
|
||||
title: 'Blog nicht gefunden | YourPart',
|
||||
description: 'Der angeforderte Blog konnte nicht geladen werden.',
|
||||
title: this.$t('blog.view.notFoundTitle'),
|
||||
description: this.$t('blog.view.notFoundDescription'),
|
||||
canonicalPath: '/blogs',
|
||||
robots: 'noindex, nofollow',
|
||||
});
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<div class="account-settings">
|
||||
<section class="account-settings__hero surface-card">
|
||||
<span class="account-settings__eyebrow">Einstellungen</span>
|
||||
<span class="account-settings__eyebrow">{{ $t("settings.account.heroEyebrow") }}</span>
|
||||
<h2>{{ $t("settings.account.title") }}</h2>
|
||||
<p>Benutzername, E-Mail, Passwort und Sichtbarkeit an einer Stelle pflegen.</p>
|
||||
<p>{{ $t("settings.account.heroIntro") }}</p>
|
||||
</section>
|
||||
|
||||
<section class="account-settings__panel surface-card">
|
||||
@@ -22,7 +22,7 @@
|
||||
<span>{{ $t("settings.account.newpassword") }}</span>
|
||||
<input type="password" v-model="newpassword" :placeholder="$t('settings.account.newpassword')"
|
||||
autocomplete="new-password" :class="{ 'field-error': newpassword && !isNewPasswordValid }" />
|
||||
<span v-if="newpassword && !isNewPasswordValid" class="form-error">Das neue Passwort sollte mindestens 8 Zeichen haben.</span>
|
||||
<span v-if="newpassword && !isNewPasswordValid" class="form-error">{{ $t("settings.account.validation.newPasswordTooShort") }}</span>
|
||||
</label>
|
||||
|
||||
<label class="account-settings__field">
|
||||
@@ -30,14 +30,14 @@
|
||||
<input type="password" v-model="newpasswordretype"
|
||||
:placeholder="$t('settings.account.newpasswordretype')" autocomplete="new-password"
|
||||
:class="{ 'field-error': newpasswordretype && !passwordsMatch }" />
|
||||
<span v-if="newpasswordretype && !passwordsMatch" class="form-error">Die Passwörter stimmen nicht überein.</span>
|
||||
<span v-if="newpasswordretype && !passwordsMatch" class="form-error">{{ $t("settings.account.validation.passwordMismatch") }}</span>
|
||||
</label>
|
||||
|
||||
<label class="account-settings__field account-settings__field--full">
|
||||
<span>{{ $t("settings.account.oldpassword") }}</span>
|
||||
<input type="password" v-model="oldpassword" :placeholder="$t('settings.account.oldpassword')"
|
||||
autocomplete="current-password" :class="{ 'field-error': requiresOldPassword && !oldpassword.trim() }" />
|
||||
<span v-if="requiresOldPassword && !oldpassword.trim()" class="form-error">Zum Passwortwechsel wird das aktuelle Passwort benötigt.</span>
|
||||
<span v-if="requiresOldPassword && !oldpassword.trim()" class="form-error">{{ $t("settings.account.validation.oldPasswordRequired") }}</span>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
@@ -149,18 +149,18 @@ export default {
|
||||
|
||||
if (hasNewPassword) {
|
||||
if (!this.isNewPasswordValid) {
|
||||
showError(this, 'Das neue Passwort ist noch zu kurz.');
|
||||
showError(this, 'tr:settings.account.validation.newPasswordTooShort');
|
||||
return;
|
||||
}
|
||||
// Validiere Passwort-Wiederholung nur wenn ein neues Passwort eingegeben wurde
|
||||
if (!this.passwordsMatch) {
|
||||
showError(this, 'Die Passwörter stimmen nicht überein.');
|
||||
showError(this, 'tr:settings.account.validation.passwordMismatch');
|
||||
return;
|
||||
}
|
||||
|
||||
// Prüfe ob das alte Passwort eingegeben wurde
|
||||
if (!this.oldpassword || this.oldpassword.trim() === '') {
|
||||
showError(this, 'Bitte geben Sie Ihr aktuelles Passwort ein, um das Passwort zu ändern.');
|
||||
showError(this, 'tr:settings.account.validation.oldPasswordRequired');
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -184,7 +184,7 @@ export default {
|
||||
// API-Aufruf zum Speichern der Account-Einstellungen
|
||||
await apiClient.post('/api/settings/set-account', accountData);
|
||||
|
||||
showSuccess(this, 'Account-Einstellungen erfolgreich gespeichert.');
|
||||
showSuccess(this, 'tr:settings.account.feedback.saved');
|
||||
|
||||
// Leere die Passwort-Felder nach erfolgreichem Speichern
|
||||
this.newpassword = '';
|
||||
@@ -193,7 +193,7 @@ export default {
|
||||
|
||||
} catch (error) {
|
||||
console.error('Fehler beim Speichern der Account-Einstellungen:', error);
|
||||
showApiError(this, error, 'Ein Fehler ist beim Speichern der Account-Einstellungen aufgetreten.');
|
||||
showApiError(this, error, 'tr:settings.account.feedback.saveError');
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -188,6 +188,7 @@ export default {
|
||||
try {
|
||||
// Mappe UI-Sprache zu vocab_language Name
|
||||
const languageMap = {
|
||||
'ceb': 'Bisaya',
|
||||
'de': 'Deutsch',
|
||||
'en': 'Englisch',
|
||||
'es': 'Spanisch',
|
||||
@@ -489,51 +490,45 @@ export default {
|
||||
|
||||
.course-actions button {
|
||||
padding: 6px 14px;
|
||||
border: 1px solid #ddd;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
background: white;
|
||||
background: var(--color-primary);
|
||||
color: #2b1f14;
|
||||
box-shadow: 0 6px 14px rgba(248, 162, 43, 0.18);
|
||||
cursor: pointer;
|
||||
font-size: 0.9em;
|
||||
white-space: nowrap;
|
||||
transition: background-color 0.2s, border-color 0.2s;
|
||||
transition: background-color 0.2s, border-color 0.2s, box-shadow 0.2s;
|
||||
}
|
||||
|
||||
.course-actions button:hover {
|
||||
background: #f5f5f5;
|
||||
border-color: #bbb;
|
||||
background: var(--color-primary-hover);
|
||||
box-shadow: 0 10px 18px rgba(248, 162, 43, 0.22);
|
||||
}
|
||||
|
||||
.btn-enroll {
|
||||
background: #4CAF50 !important;
|
||||
color: white !important;
|
||||
border-color: #4CAF50 !important;
|
||||
}
|
||||
|
||||
.btn-enroll:hover {
|
||||
background: #45a049 !important;
|
||||
border-color: #45a049 !important;
|
||||
background: var(--color-primary) !important;
|
||||
color: #2b1f14 !important;
|
||||
border-color: transparent !important;
|
||||
}
|
||||
|
||||
.btn-continue {
|
||||
background: #2196F3 !important;
|
||||
color: white !important;
|
||||
border-color: #2196F3 !important;
|
||||
}
|
||||
|
||||
.btn-continue:hover {
|
||||
background: #0b7dda !important;
|
||||
border-color: #0b7dda !important;
|
||||
background: var(--color-primary) !important;
|
||||
color: #2b1f14 !important;
|
||||
border-color: transparent !important;
|
||||
}
|
||||
|
||||
.btn-edit {
|
||||
background: #FF9800 !important;
|
||||
color: white !important;
|
||||
border-color: #FF9800 !important;
|
||||
background: rgba(255, 255, 255, 0.9) !important;
|
||||
color: var(--color-text-primary) !important;
|
||||
border-color: var(--color-border) !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.btn-edit:hover {
|
||||
background: #e68900 !important;
|
||||
border-color: #e68900 !important;
|
||||
background: rgba(255, 255, 255, 0.98) !important;
|
||||
border-color: var(--color-border-strong) !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.dialog-overlay {
|
||||
|
||||
@@ -526,20 +526,20 @@ export default {
|
||||
|
||||
.btn-current-lesson {
|
||||
padding: 12px 24px;
|
||||
background: var(--color-primary-orange);
|
||||
color: #000000;
|
||||
border: 1px solid var(--color-primary-orange);
|
||||
background: var(--color-primary);
|
||||
color: #2b1f14;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 1em;
|
||||
font-weight: 600;
|
||||
transition: background 0.05s;
|
||||
transition: background 0.2s, box-shadow 0.2s;
|
||||
box-shadow: 0 6px 14px rgba(248, 162, 43, 0.18);
|
||||
}
|
||||
|
||||
.btn-current-lesson:hover {
|
||||
background: #FFF4F0;
|
||||
color: #5D4037;
|
||||
border: 1px solid #5D4037;
|
||||
background: var(--color-primary-hover);
|
||||
box-shadow: 0 10px 18px rgba(248, 162, 43, 0.22);
|
||||
}
|
||||
|
||||
.lesson-cards {
|
||||
@@ -675,20 +675,20 @@ export default {
|
||||
|
||||
.btn-start {
|
||||
padding: 8px 16px;
|
||||
background: var(--color-primary-orange);
|
||||
color: #000000;
|
||||
border: 1px solid var(--color-primary-orange);
|
||||
background: var(--color-primary);
|
||||
color: #2b1f14;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 0.9em;
|
||||
font-weight: 500;
|
||||
transition: background 0.05s;
|
||||
transition: background 0.2s, box-shadow 0.2s;
|
||||
box-shadow: 0 6px 14px rgba(248, 162, 43, 0.18);
|
||||
}
|
||||
|
||||
.btn-start:hover:not(:disabled) {
|
||||
background: #FFF4F0;
|
||||
color: #5D4037;
|
||||
border: 1px solid #5D4037;
|
||||
background: var(--color-primary-hover);
|
||||
box-shadow: 0 10px 18px rgba(248, 162, 43, 0.22);
|
||||
}
|
||||
|
||||
.btn-start:disabled {
|
||||
@@ -701,26 +701,26 @@ export default {
|
||||
|
||||
.btn-edit {
|
||||
padding: 6px 12px;
|
||||
background: var(--color-primary-orange);
|
||||
color: #000000;
|
||||
border: 1px solid var(--color-primary-orange);
|
||||
background: rgba(255, 255, 255, 0.9);
|
||||
color: var(--color-text-primary);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 0.85em;
|
||||
transition: background 0.05s;
|
||||
transition: background 0.2s, border-color 0.2s;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.btn-edit:hover {
|
||||
background: #FFF4F0;
|
||||
color: #5D4037;
|
||||
border: 1px solid #5D4037;
|
||||
background: rgba(255, 255, 255, 0.98);
|
||||
border: 1px solid var(--color-border-strong);
|
||||
}
|
||||
|
||||
.btn-delete {
|
||||
padding: 6px 12px;
|
||||
background: #dc3545;
|
||||
background: rgba(177, 59, 53, 0.92);
|
||||
color: white;
|
||||
border: none;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 0.85em;
|
||||
@@ -728,7 +728,7 @@ export default {
|
||||
}
|
||||
|
||||
.btn-delete:hover {
|
||||
background: #c82333;
|
||||
background: var(--color-danger-hover);
|
||||
}
|
||||
|
||||
.dialog-overlay {
|
||||
|
||||
@@ -947,6 +947,14 @@ export default {
|
||||
return;
|
||||
}
|
||||
this.activeTab = 'exercises';
|
||||
this.$nextTick(() => {
|
||||
const scrollEl = document.querySelector('.app-content__scroll.contentscroll');
|
||||
if (scrollEl) {
|
||||
scrollEl.scrollTop = 0;
|
||||
} else {
|
||||
window.scrollTo(0, 0);
|
||||
}
|
||||
});
|
||||
},
|
||||
updateExerciseUnlockState() {
|
||||
if (this.exercisePreparationCompleted) {
|
||||
@@ -2353,10 +2361,12 @@ export default {
|
||||
|
||||
.btn-back {
|
||||
padding: 8px 16px;
|
||||
border: 1px solid #ddd;
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 4px;
|
||||
background: white;
|
||||
background: rgba(255, 255, 255, 0.92);
|
||||
color: var(--color-text-primary);
|
||||
cursor: pointer;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.lesson-description {
|
||||
@@ -2447,18 +2457,20 @@ export default {
|
||||
|
||||
.exercise-item button {
|
||||
padding: 10px 20px;
|
||||
background: #4CAF50;
|
||||
color: white;
|
||||
border: none;
|
||||
background: var(--color-primary);
|
||||
color: #2b1f14;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 1em;
|
||||
margin-top: 10px;
|
||||
transition: background-color 0.2s;
|
||||
transition: background-color 0.2s, box-shadow 0.2s;
|
||||
box-shadow: 0 6px 14px rgba(248, 162, 43, 0.18);
|
||||
}
|
||||
|
||||
.exercise-item button:hover:not(:disabled) {
|
||||
background: #45a049;
|
||||
background: var(--color-primary-hover);
|
||||
box-shadow: 0 10px 18px rgba(248, 162, 43, 0.22);
|
||||
}
|
||||
|
||||
.exercise-item button:disabled {
|
||||
@@ -2513,24 +2525,26 @@ export default {
|
||||
|
||||
.tab-button {
|
||||
padding: 10px 20px;
|
||||
border: none;
|
||||
background: transparent;
|
||||
border: 1px solid transparent;
|
||||
background: rgba(255, 255, 255, 0.72);
|
||||
cursor: pointer;
|
||||
font-size: 1em;
|
||||
color: #666;
|
||||
color: var(--color-text-secondary);
|
||||
border-bottom: 2px solid transparent;
|
||||
margin-bottom: -2px;
|
||||
transition: all 0.2s;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.tab-button:hover:not(:disabled) {
|
||||
color: #333;
|
||||
background: #f5f5f5;
|
||||
color: var(--color-text-primary);
|
||||
background: rgba(255, 255, 255, 0.92);
|
||||
}
|
||||
|
||||
.tab-button.active {
|
||||
color: #007bff;
|
||||
border-bottom-color: #007bff;
|
||||
color: #2b1f14;
|
||||
background: var(--color-primary);
|
||||
border-bottom-color: var(--color-primary);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
@@ -2687,17 +2701,18 @@ export default {
|
||||
|
||||
.btn-start-trainer {
|
||||
padding: 10px 20px;
|
||||
background: #4CAF50;
|
||||
color: white;
|
||||
border: none;
|
||||
background: var(--color-primary);
|
||||
color: #2b1f14;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 1em;
|
||||
margin-top: 10px;
|
||||
box-shadow: 0 6px 14px rgba(248, 162, 43, 0.18);
|
||||
}
|
||||
|
||||
.btn-start-trainer:hover {
|
||||
background: #45a049;
|
||||
background: var(--color-primary-hover);
|
||||
}
|
||||
|
||||
.vocab-trainer-stats {
|
||||
@@ -2733,8 +2748,8 @@ export default {
|
||||
}
|
||||
|
||||
.mode-badge.mode-active {
|
||||
background: #007bff;
|
||||
color: white;
|
||||
background: var(--color-primary);
|
||||
color: #2b1f14;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
@@ -2745,16 +2760,16 @@ export default {
|
||||
|
||||
.btn-stop-trainer {
|
||||
padding: 5px 15px;
|
||||
background: #dc3545;
|
||||
background: rgba(177, 59, 53, 0.92);
|
||||
color: white;
|
||||
border: none;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.btn-stop-trainer:hover {
|
||||
background: #c82333;
|
||||
background: var(--color-danger-hover);
|
||||
}
|
||||
|
||||
.vocab-question {
|
||||
@@ -2802,20 +2817,20 @@ export default {
|
||||
|
||||
.btn-switch-mode {
|
||||
padding: 8px 16px;
|
||||
background: var(--color-primary-orange);
|
||||
color: #000000;
|
||||
border: 1px solid var(--color-primary-orange);
|
||||
background: rgba(255, 255, 255, 0.92);
|
||||
color: var(--color-text-primary);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 0.9em;
|
||||
font-weight: 500;
|
||||
transition: background 0.05s;
|
||||
transition: background 0.2s, border-color 0.2s;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
.btn-switch-mode:hover {
|
||||
background: var(--color-primary-orange-light);
|
||||
color: var(--color-text-secondary);
|
||||
border: 1px solid var(--color-text-secondary);
|
||||
background: rgba(255, 255, 255, 0.98);
|
||||
border: 1px solid var(--color-border-strong);
|
||||
}
|
||||
|
||||
.vocab-answer-area.multiple-choice {
|
||||
@@ -2842,14 +2857,14 @@ export default {
|
||||
}
|
||||
|
||||
.choice-button:hover {
|
||||
border-color: #007bff;
|
||||
background: #f0f8ff;
|
||||
border-color: var(--color-primary);
|
||||
background: rgba(248, 162, 43, 0.08);
|
||||
}
|
||||
|
||||
.choice-button.selected {
|
||||
border-color: #007bff;
|
||||
background: #007bff;
|
||||
color: white;
|
||||
border-color: var(--color-primary);
|
||||
background: var(--color-primary);
|
||||
color: #2b1f14;
|
||||
}
|
||||
|
||||
.vocab-input {
|
||||
@@ -2862,16 +2877,16 @@ export default {
|
||||
|
||||
.btn-check {
|
||||
padding: 10px 20px;
|
||||
background: #4CAF50;
|
||||
color: white;
|
||||
border: none;
|
||||
background: var(--color-primary);
|
||||
color: #2b1f14;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.btn-check:hover:not(:disabled) {
|
||||
background: #45a049;
|
||||
background: var(--color-primary-hover);
|
||||
}
|
||||
|
||||
.btn-check:disabled {
|
||||
@@ -2903,16 +2918,16 @@ export default {
|
||||
|
||||
.vocab-next button {
|
||||
padding: 10px 20px;
|
||||
background: #007bff;
|
||||
color: white;
|
||||
border: none;
|
||||
background: var(--color-primary);
|
||||
color: #2b1f14;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.vocab-next button:hover {
|
||||
background: #0056b3;
|
||||
background: var(--color-primary-hover);
|
||||
}
|
||||
|
||||
.vocab-info-text {
|
||||
@@ -2936,9 +2951,9 @@ export default {
|
||||
|
||||
.btn-continue {
|
||||
padding: 12px 24px;
|
||||
background: #007bff;
|
||||
color: white;
|
||||
border: none;
|
||||
background: var(--color-primary);
|
||||
color: #2b1f14;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
font-size: 1.1em;
|
||||
cursor: pointer;
|
||||
@@ -2946,7 +2961,7 @@ export default {
|
||||
}
|
||||
|
||||
.btn-continue:hover {
|
||||
background: #0056b3;
|
||||
background: var(--color-primary-hover);
|
||||
}
|
||||
|
||||
/* Reading Aloud & Speaking From Memory Styles */
|
||||
@@ -2981,12 +2996,12 @@ export default {
|
||||
}
|
||||
|
||||
.btn-record {
|
||||
background: #28a745;
|
||||
color: white;
|
||||
background: var(--color-primary);
|
||||
color: #2b1f14;
|
||||
}
|
||||
|
||||
.btn-record:hover:not(:disabled) {
|
||||
background: #218838;
|
||||
background: var(--color-primary-hover);
|
||||
}
|
||||
|
||||
.btn-record:disabled {
|
||||
@@ -2995,26 +3010,26 @@ export default {
|
||||
}
|
||||
|
||||
.btn-stop-record {
|
||||
background: #dc3545;
|
||||
background: rgba(177, 59, 53, 0.92);
|
||||
color: white;
|
||||
}
|
||||
|
||||
.btn-stop-record:hover {
|
||||
background: #c82333;
|
||||
background: var(--color-danger-hover);
|
||||
}
|
||||
|
||||
.btn-check {
|
||||
padding: 10px 20px;
|
||||
background: #007bff;
|
||||
color: white;
|
||||
border: none;
|
||||
background: var(--color-primary);
|
||||
color: #2b1f14;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 6px;
|
||||
cursor: pointer;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
.btn-check:hover {
|
||||
background: #0056b3;
|
||||
background: var(--color-primary-hover);
|
||||
}
|
||||
|
||||
.recording-status {
|
||||
@@ -3150,16 +3165,16 @@ export default {
|
||||
|
||||
.dialog-button {
|
||||
padding: 8px 16px;
|
||||
background: #007bff;
|
||||
color: white;
|
||||
border: none;
|
||||
background: var(--color-primary);
|
||||
color: #2b1f14;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.dialog-button:hover {
|
||||
background: #0056b3;
|
||||
background: var(--color-primary-hover);
|
||||
}
|
||||
|
||||
@media (max-width: 900px) {
|
||||
|
||||
Reference in New Issue
Block a user