diff --git a/src/i18n/fr.ts b/src/i18n/fr.ts
new file mode 100644
index 00000000..018db561
--- /dev/null
+++ b/src/i18n/fr.ts
@@ -0,0 +1,551 @@
+export const i18nFR = {
+ elements: {
+ campaign_one: "Campaign",
+ campaign_other: "Campaigns",
+ campaing_inside: "Inside Campaign",
+ campaign_contains: "Contains Campaigns",
+ adventure_one: "Adventure",
+ adventure_other: "Adventures",
+ adventure_inside: "Inside Adventure",
+ adventure_contains: "Contains Adventures",
+ session_one: "Session",
+ session_other: "Sessions",
+ session_inside: "Inside Session",
+ session_contains: "Contains Sessions",
+ chapter_one: "Chapter",
+ chapter_other: "Chapters",
+ chapter_inside: "Inside Chapter",
+ chapter_contains: "Contains Chapters",
+ scene_one: "Scene",
+ scene_other: "Scenes",
+ scene_inside: "Inside Scene",
+ scene_contains: "Contains Scenes",
+ playercharacter_one: "Player character",
+ playercharacter_other: "Player characters",
+ playercharacter_inside: "Inside Player Character",
+ playercharacter_contains: "Contains Player Characters",
+ nonplayercharacter_one: "Non-player character",
+ nonplayercharacter_other: "Non-player characters",
+ nonplayercharacter_inside: "Inside Non-Player Character",
+ nonplayercharacter_contains: "Contains Non-Player Characters",
+ location_one: "Location",
+ location_other: "Locations",
+ location_inside: "Inside Location",
+ location_contains: "Contains Locations",
+ faction_one: "Faction",
+ faction_other: "Factions",
+ faction_inside: "Inside Faction",
+ faction_contains: "Contains Factions",
+ event_one: "Event",
+ event_other: "Events",
+ event_inside: "Inside Event",
+ event_contains: "Contains Events",
+ clue_one: "Clue",
+ clue_other: "Clues",
+ clue_inside: "Inside Clue",
+ clue_contains: "Contains Clues",
+ subplot_one: "Subplot",
+ subplot_other: "Subplots",
+ subplot_inside: "Inside Subplot",
+ subplot_contains: "Contains Subplots",
+ object_one: "Object",
+ object_other: "Objects",
+ object_inside: "Inside Object",
+ object_contains: "Contains Objects",
+ monster_one: "Monster",
+ monster_other: "Monsters",
+ monster_inside: "Inside Monster",
+ monster_contains: "Contains Monsters",
+ element_one: "Element",
+ element_other: "Elements",
+ },
+ tasks: {
+ task_one: "Task",
+ task_other: "Tasks",
+ owned: "{{variable}}'s tasks",
+ name: "Name",
+ priority: "Priority",
+ mentionedin: "Mentioned in",
+ description: "Description",
+ assignedto: "Assigned to",
+ all: "All tasks",
+ complete_campaign: "Complete Campaign",
+ complete_adventure: "Complete Adventure",
+ complete_session: "Complete Session",
+ complete_chapter: "Complete Chapter",
+ complete_scene: "Complete Scene",
+ complete_playercharacter: "Complete Player Character",
+ complete_nonplayercharacter: "Complete Non-Player Character",
+ complete_location: "Complete Location",
+ complete_faction: "Complete Faction",
+ complete_event: "Complete Event",
+ complete_clue: "Complete Clue",
+ complete_subplot: "Complete Subplot",
+ complete_object: "Complete Object",
+ complete_monster: "Complete Monster",
+ complete_element: "Complete Element",
+ },
+ customattributes: {
+ name: "Name",
+ type: "Type",
+ text: "Text",
+ number: "Number",
+ option: "Option",
+ checkbox: "Checkbox",
+ longtext: "Long Text",
+ link: "Link",
+ date: "Date",
+ availableon: "Available on",
+ your: "Your Custom Attributes",
+ describe: `You can customise the attributes to use in your elements.
+
+On the left you can see the attributes you have already created, and you can edit them.
+
+If you want to create new ones, just click on the button and define the name and type of the attribute and in which elements it is goign to be available.`,
+ cantdelete: "You can't delete this attribute because it is used in one or more elements.",
+ },
+ attributes: {
+ attribute_one: "Attribute",
+ attribute_other: "Attributes",
+ description: "Description",
+ ghost: "Ghost",
+ lie: "Lie",
+ arc: "Character Arc",
+ beliefs: "Beliefs",
+ need: "Need",
+ behaviour: "Behaviour",
+ want: "Want",
+ opposition: "Opposition",
+ strengths: "Strengths",
+ weaknesses: "Weaknesses",
+ storycircle: "Story Circle",
+ scenetype: "Type",
+ dob: "Date of Birth",
+ dod: "Date of Death",
+ sceneaction: "Action",
+ date: "Date",
+ sessiondate: "Session Date",
+ storycirclestage: "Story Circle Stage",
+ abtstage: "ABT Stage",
+ externalactions: "Exciting",
+ address: "Address",
+ location: "Location",
+ duration: "Duration",
+ philosophy: "Philosophy",
+ majorclues: "Major Clues",
+ factionstructure: "Faction Structure",
+ nonplayercharactertype: "NPC Type",
+ sensoryimprint: "Sensory Imprint",
+ custom: "Custom Attributes",
+ stage: "Stage",
+ coordinates: "Coordinates",
+ sensoryimprints: "Sensory Imprints",
+ active: " (Active)",
+ occupation: "Occupation",
+ stake: "Stake",
+ goals: "Goals (Want)",
+ attitude: "Attitude (Behaviour)",
+ kishotenketsu: "Kishōtenketsu",
+ conflict: "Conflict",
+ pronoun: "Pronoun",
+ },
+ npctype: {
+ npctype_main: "Main",
+ npctype_supporting: "Supporting",
+ npctype_extra: "Extra",
+ description_main: "A fully fledged non-player character, with details about their personality, wants and needs.",
+ description_supporting: "A recurring non-player character that is not a main character.",
+ description_extra: "A non-player character with minimal details, just enough to be used as a background character.",
+ },
+ arc: {
+ arc_1: "Positive Arc",
+ arc_2: "Disillusionment Arc",
+ arc_3: "Fall Arc",
+ arc_4: "Corruption Arc",
+ arc_5: "Flat Arc",
+ description_1:
+ "The character starts **believing a lie**, they then encounter the truth and overcome the lie and **accept the truth**.",
+ description_2:
+ "The character starts **believing a lie**, they then encounter the truth and overcome the lie, but **the truth leads to worse outcome** than in believing the lie.",
+ description_3:
+ "The character starts **believing a lie**, they then encounter the truth but reject it and **believing a stronger or worse lie**.",
+ description_4: "The character starts **knowing the truth**, but then they reject the truth, **embracing a lie**.",
+ description_5:
+ "The character starts **knowing the truth**, but then their beliefs are tested, but they keep **embracing the truth**.",
+ },
+ options: {
+ option_one: "Option",
+ option_other: "Options",
+ wizard: "Wizard",
+ },
+ search: {
+ entertocreate: "Enter to create",
+ },
+ parents: {
+ parent_campaign: "Part of Campaign",
+ parent_adventure: "Part of Adventure",
+ parent_session: "Part of Session",
+ },
+ relationships: {
+ relationship_other: "Relationships",
+ relationship_one: "Relationship",
+ relationshiptype: "Relationship Type",
+ relationshiptype_reverse: "Reversed",
+ relationshiptype_bidirectional: "Bidirectional",
+ relationshiptype_unidirectional: "Unidirectional",
+ relationshiptype_parent: "Parent",
+ relationshiptype_child: "Child",
+ },
+ gallery: {
+ title: "Image Gallery",
+ drag: "Drag a new image",
+ dragdrop: "Drag and drop image here",
+ upload: "Upload a new image",
+ link: "Link a new image",
+ browse: "Browse images",
+ browselocal: "Browse local images",
+ caption: "Caption",
+ carousel: "Image Carousel",
+ },
+ analyser: {
+ expectedduration: "Expected Duration",
+ activity: "Activity",
+ excitement: "Excitement",
+ interest: "Interest",
+ variety: "Variety",
+ sceneanalyser: "Scene Analyser",
+ saactivity_positiveerror: "Too many active scenes",
+ saactivity_positivewarnign: "The number of active scenes might be more than needed.",
+ saactivity_negativeerror: "Not enough active scenes",
+ saactivity_negativewarning: "The number of active scenes could not be enough.",
+ saexcitement_positiveerror: "Too many exciting scenes",
+ saexcitement_positivewarnign: "The number of exciting scenes might be more than needed.",
+ saexcitement_negativeerror: "Not enough exciting scenes",
+ saexcitement_negativewarning: "The number of exciting scenes could not be enough.",
+ sainterest_negativeerror: "Not enough variety in the type of scenes",
+ sainterest_negativewarning: "The number of scene types could not be enough.",
+ savariety_negativeerror: "Too many repeated scene types",
+ savariety_negativewarning: "The number of repeated scene types could be too high.",
+ },
+ clues: {
+ description: "Description",
+ destination: "Destination",
+ },
+ buttons: {
+ save: "Save",
+ edit: "Edit",
+ delete: "Delete",
+ cancel: "Cancel",
+ create: "Create",
+ replace: "Replace",
+ adddestination: "Add Destination",
+ newattribute: "New Attribute",
+ assign: "Assign",
+ unassign: "Unassign",
+ launchwizard: "Launch Creation Wizard",
+ previous: "< Previous",
+ next: "Next >",
+ },
+ create: {
+ title: "Create New...",
+ in_title: "Convert to...",
+ new_campaign: "Create new Campaign",
+ new_adventure: "Create new Adventure",
+ new_session: "Create new Session",
+ new_chapter: "Create new chapter",
+ new_scene: "Create new Scene",
+ new_element: "Create new Rpg Manager Element",
+ new_task: "Create new Task",
+ new_playercharacter: "Create new Player Character",
+ new_nonplayercharacter: "Create new Non-Player Character",
+ new_location: "Create new Location",
+ new_faction: "Create new Faction",
+ new_event: "Create new Event",
+ new_clue: "Create new Clue",
+ new_subplot: "Create new Subplot",
+ new_object: "Create new Object",
+ new_monster: "Create new Monster",
+ in_element: "Add a new Rpg Manager Element to the current note",
+ in_campaign: "Add a new Campaign to the current note",
+ in_adventure: "Add a new Adventure to the current note",
+ in_session: "Add a new Session to the current note",
+ in_chapter: "Add a new Chapter to the current note",
+ in_scene: "Add a new Scene to the current note",
+ in_playercharacter: "Add a new Player Character to the current note",
+ in_nonplayercharacter: "Add a new Non-Player Character to the current note",
+ in_location: "Add a new Location to the current note",
+ in_faction: "Add a new Faction to the current note",
+ in_event: "Add a new Event to the current note",
+ in_clue: "Add a new Clue to the current note",
+ in_subplot: "Add a new Subplot to the current note",
+ in_object: "Add a new Object to the current note",
+ in_monster: "Add a new Monster to the current note",
+ add_session: "Add new Session",
+ add_scene: "Add new Scene",
+ add_chapter: "Add new Chapter",
+ add_task: "Add new Task",
+ add_clue: "Add Clue",
+ add_relationship: "Add Relationship",
+ add_attribute: "Add Attribute",
+ select_campaign: "Select Campaign",
+ select_adventure: "Select Adventure",
+ select_session: "Select Session",
+ select_type: "Select the type of element you want to create",
+ select_template: "Select the template for your element",
+ },
+ chatgpt: {
+ overlaytitle_nonplayercharacter: "Automatically Generating your Character",
+ overlaytitle_chapter: "Automatically Generating your Chapter",
+ overlaydescription: "This may take a while, please be patient and wait for the process to complete.",
+ generate: "Generate with ChatGPT",
+ messages: [
+ "Retrieving suggestions from ChatGPT...",
+ "Waiting for ChatGPT to think...",
+ "Having a coffee while I wait...",
+ "The pidgeon carrying your suggestion might have been eaten by a red dragon...",
+ "Shall we talk about Call of Cthulhu while we wait?",
+ "Yes, I am STILL waiting!",
+ "Yes, I am STILL waiting! (I am not a very patient bot)",
+ "Did you know that the first ever game of D&D was played by Gary Gygax and Dave Arneson in 1974?",
+ "Do you often yawn while waiting for ChatGPT?",
+ "The creator of this plugin is the BEST storyteller I know! (yet it is the only one I know...)",
+ "ChatGPT is late, roll initiative!",
+ "Why did the NPC cross the road? To escape the bard's bad puns!",
+ "If you have any spare 20-sided dice, now would be a good time to roll for patience.",
+ "I'd ask a wizard for help, but they're notorious for their late replies.",
+ "Summoning a friendly chat entity... Do not cast 'Dispel Magic'!",
+ "Still waiting for the bard to finish their solo...",
+ "Do dragons even use ChatGPT? Asking for a friend.",
+ "How many elves does it take to get a response? Just one, but they'll tell a long tale about it.",
+ "Sorry for the delay. A rogue tried to pickpocket my code.",
+ "Did the sorcerer hex my connection again?",
+ "In a land far, far away... ChatGPT is still thinking.",
+ "A wizard is never late, nor is he early. But ChatGPT... sometimes takes its sweet time.",
+ "Facing off with a gelatinous cube. Might take a while...",
+ "I told the barbarian to 'wait here'. He's still standing there...",
+ ],
+ },
+ wizards: {
+ errors: "The following errors have been found:",
+ chapter: {
+ errors: {
+ missingtargettype: "Please select a target type",
+ missingtargetname: "Please enter a target name or select an existing one",
+ missingdestination: "Please select either a valid destination or type the new destination name",
+ },
+ cluename: "Clue name",
+ cluesdescription: "Description of the clue(s)",
+ title: "Chapter Wizard",
+ description: `A chapter is a way to organise bigger adventures in more manageable chunks, like for a book or a film.
+
+Describe *{{name}}*.`,
+ destinationtitle: "Destination",
+ destination: "Where does this chapter lead to?",
+ destinationelementtype: "Destination type",
+ destinationtype_adventure: "The next step from here should be another adventure",
+ destinationtype_chapter: "This chapter should lead to another chapter",
+ destinationelementtype_existing: "Existing",
+ destinationelementtypedescription_existing: "Select an existing adventure or chapter to follow this one.",
+ destinationelementtype_new: "New",
+ destinationelementtypedescription_new: "The adventure or chapter to follow this one is a new one.",
+ destinationelement_existing: "Existing destination adventure or chapter",
+ destinationelement_new: "New destination adventure or chapter name",
+ targettitle: "Target",
+ target: "Is the chapter targeting an event or a location to move the plot forward?",
+ targetdescription: "Before describing the target, please select the type of target you want to use.",
+ targettitle_event: "Description of the key event",
+ targetdescription_event: "Write a description for the key event in chapter *{{name}}*",
+ targettitle_location: "Description of the key location",
+ targetdescription_location: "Write a description for the key location in chapter *{{name}}*",
+ targetelementtype: "Target type",
+ targettype_event: "The plot is moved forward by an event",
+ targettype_location: "The chapter revolves around a location",
+ targetelementtype_existing: "Existing",
+ targetelementtypedescription_existing: "Select an existing event or location where to pivot the chapter.",
+ targetelementtype_new: "New",
+ targetelementtypedescription_new: "The event or location is a new one.",
+ targetelement_existing: "Existing target event or location",
+ targetelement_new: "New target event or location name",
+ targetelementdescription: "Description of the event or the location",
+ removeexistingclue: "Remove",
+ selectexistingclue: "Select existing clue",
+ },
+ npc: {
+ title: "Non-Player Character Wizard",
+ create: "Create automatically",
+ description_arc: `The character arc describe the way a character grow and evolve during the story.
+
+Please **select the arc** that better identifies *{{name}}*'s evolution.`,
+ description_behaviour: `The behaviour is the normal way a character does things, the way the player characters see them.
+
+What is the Behaviour of *{{name}}*?`,
+ description_beliefs: `The Beliefs is what characters accept to be true in the world, even if they are not.
+
+What are the beliefs of *{{name}}*?`,
+ description_description: `The description is an introduction to a character, giving a blurb of background information to help the
+storyteller to clearly identify them. This part is particularly importan if you wish to use the automatic character generation via the AI feature.
+
+Describe *{{name}}*.`,
+ description_occupation: `The occupation defines what a character does for living. While this does not define who they are,
+it adds a layer of depth to the character and suggests a set of skill they possess.
+
+What's *{{name}}* occupation?`,
+ description_ghost: `The Ghost is an important event in the character's past that defines their beliefs.
+The ghost is highly likely a turning point, highly positive or highly negative and may have shaped their view of the world as a lie.
+
+What is the event that shaped *{{name}}*?`,
+ description_lie: `The Lie is what a character believes about the world to be true that is not.
+
+What is the lie *{{name}}* believs in?`,
+ description_need: `The Need is what a charater truly need, even it it is unknown to them.
+
+What does *{{name}}* desperately needs?`,
+ description_opposition: `The Oppositon are forces that stops the character to get what they want.
+
+What is opposing *{{name}}* from reaching what they want?`,
+ description_strengths: `Strengths are the positive traits of a character.
+
+Select *{{name}}*'s.`,
+ description_weaknesses: `Weaknesses are the negative traits of a character.
+
+Select *{{name}}*'s.`,
+ description_type: `The type of character defines their importance in the campaign and the amount of attributes they have by default.
+
+Who is *{{name}}*?`,
+ description_want: `The Want is what characters think they want to achieve, even if it is not what they really need. This is pulicly known and determines their behaviour.
+
+What does *{{name}}* wants?`,
+ description_stake: `The Stake defines a value of how much the character is **invested** in their occupation, wants and behaviours.
+This helps defining how much effort they will put into achieving them.
+
+What's *{{name}}* stake?`,
+ },
+ },
+ errors: {
+ must_campaign: "You must create a campaign first",
+ must_adventure: "You must create an adventure first",
+ must_session: "You must create a session first",
+ },
+ kishotenketsu: {
+ ki: "Ki
(Introduction)",
+ sho: "Shō
(Development)",
+ ten: "Ten
(Twist)",
+ ketsu: "Ketsu
(Conclusion)",
+ description_ki:
+ "**Introduction**: an introduction to the characters, era, and other information required to understand the plot",
+ description_sho: "**Development**: follows leads towards the twist in the story. No major changes so far.",
+ description_ten:
+ "**Twist**: the story turns toward an unexpected development. This is the crux of the story, the yama (ヤマ) or climax. If the narrative takes several turns, this is the biggest one.",
+ description_ketsu: "**Conclusion**: also called ochi (落ち) or ending, wraps up the story.",
+ },
+ storycircle: {
+ you: "You/They",
+ need: "Need",
+ go: "Go",
+ search: "Search",
+ find: "Find",
+ take: "Take",
+ return: "Return",
+ change: "Change",
+ description_you:
+ "Start by establishing the current situation of the player characters at the beginning of this particular plot. What are they currently doing? Where are they? What is their immediate goal?",
+ description_need:
+ "Make the player characters feel a need. Don't call it *hook*, make sure the player characters are invested and feel a desperate need to do something.",
+ description_go:
+ "The player characters enter a new situation. They leave their comfort zone and enter a new world. This is the point of no return.",
+ description_search:
+ "This is the stage of the challenges. The player characters are tested and they face their fears. They are forced to adapt to the new situation.",
+ description_find:
+ "The player characters highly likely have to achieve what they set off for, but they have to pay a price: what they get is what the want, but not what they need.",
+ description_take:
+ "Time to create a situation in which the player characters can switch from what they want to what they need. This is the moment of realisation.",
+ description_return:
+ "The player characters fight to get what they need, and in doing so they return to the world they know.",
+ description_change:
+ "The player characters have changed, and they should see the effect of their actions in the world they know.",
+ },
+ conflict: {
+ title: "Title",
+ description_title:
+ "This is a descriptive name for the conflict, which should help the storyteller remember what it's about.",
+ description: "Description",
+ description_description: "A description of the conflict, including how the player characters are involved.",
+ outcome: "Outcome",
+ description_outcome: "This describes the ultimate outcome of the conflict, after the conflict is played out.",
+ category: "Category",
+ description_category: `This is a broad category that helps to describe the nature of the conflict and helps the storyteller to understand what the conflict is about.
+
+- **Ambition**: The characters involved want to achieve something.
+- **Betrayal**: The conflict is about a betrayal.
+- **Survival**: It's a matter of life and death.
+- **Revenge**: The conflict is about characters' revenge.
+- **Ideology**: Everything revolves around an ideology.
+- **Love**: Personal conflict focusing on relationships.
+- **Guilt**: The conflict is about guilt.
+- **Fear**: It revolves around fear.`,
+ category_ambition: "Ambition",
+ category_betrayal: "Betrayal",
+ category_survival: "Survival",
+ category_revenge: "Revenge",
+ category_ideology: "Ideology",
+ category_love: "Love",
+ category_guilt: "Guilt",
+ category_fear: "Fear",
+ involvement: "Involvement",
+ involvement_active: "Active",
+ involvement_passive: "Passive",
+ involvement_unaware: "Unaware",
+ involvement_forced: "Forced",
+ involvement_opportunistic: "Opportunistic",
+ description_involvement: `This describes how the player characters are involved in the conflict, and helps the storyteller to understand how they can be linked to the conflict.
+
+- **Active**: The player characters are actively involved in the conflict.
+- **Passive**: The player characters are not actively involved in the conflict, but they are affected by it.
+- **Unaware**: The player characters are not aware of the conflict, but they are affected by it.
+- **Forced**: The player characters are forced to be involved in the conflict.
+- **Opportunistic**: The player characters are not involved in the conflict, but they can take advantage of it.`,
+ opposingforces: "Opposing Forces",
+ description_opposingforces:
+ "List of non-player characters or factions in the conflict. It helps the storyteller to understand who is fighting who.",
+ events: "Events",
+ description_events: "List of events that are part of the conflict.",
+ status: "Status",
+ description_status: `This describes the current status of the conflict, and helps the storyteller to understand how the conflict is developing.
+
+- **Planned**: The conflict is planned, but it has not started yet.
+- **In Progress**: The conflict is currently happening.
+- **Resolved**: The conflict has been resolved.`,
+ status_planned: "Planned",
+ status_inprogress: "In Progress",
+ status_resolved: "Resolved",
+ stakes: "Stakes",
+ description_stakes: `This describes what's at stake in the conflict, and what will happen if one side wins over the other.
+
+- **Life and Death**: Threathening someone's life.
+- **Love and Relationships**: Involving personal relationships.
+- **Power and Control**: Involving power and control over others.
+- **Reputation and Honor**: Challenging a character's honour.
+- **Wealth and Resources**: All about Money.
+- **Freedom and Justice**: Similar to Morality and Ethics, but from a justice perspective.
+- **Knowledge and Information**: Information is power.
+- **Morality and Ethics**: It's a matter of what's right and what's wrong.
+- **Beliefs and Values**: Challenging a character's beliefs.
+- **Future and Legacy**: What will be left behind.`,
+ stake: {
+ lifeanddeath: "Life and Death",
+ loveandrelationships: "Love and Relationships",
+ powerandcontrol: "Power and Control",
+ reputationandhonor: "Reputation and Honor",
+ wealthandresources: "Wealth and Resources",
+ freedomandjustice: "Freedom and Justice",
+ knowledgeandinformation: "Knowledge and Information",
+ moralityandethics: "Morality and Ethics",
+ beliefsandvalues: "Beliefs and Values",
+ futureandlegacy: "Future and Legacy",
+ },
+ },
+ name: "Name",
+ documentation: "Documentation",
+ global: "Global Asset",
+ global_description: "Make this element available in all campaigns",
+};
diff --git a/src/services/InternationalisationService.ts b/src/services/InternationalisationService.ts
index eac16990..faa7d26c 100644
--- a/src/services/InternationalisationService.ts
+++ b/src/services/InternationalisationService.ts
@@ -1,3 +1,4 @@
+import { i18nFR } from "@/i18n/fr";
import { i18nIt } from "@/i18n/it";
import i18n from "i18next";
import I18nextBrowserLanguageDetector from "i18next-browser-languagedetector";
@@ -23,6 +24,7 @@ export class InternationalisationService {
});
i18n.addResourceBundle("en", "common", i18nEn);
+ i18n.addResourceBundle("fr", "common", i18nFR);
i18n.addResourceBundle("it", "common", i18nIt);
}
}