From ebd0803c0c3e87fdbdee3d983b03db5f5297630b Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Mon, 7 Apr 2025 10:29:21 +0000 Subject: [PATCH] Fix issue #2528: Restore language option in crew configuration Co-Authored-By: Joe Moura --- src/crewai/crew.py | 12 +++++++++-- src/crewai/utilities/i18n.py | 12 +++++++++-- tests/crew_language_test.py | 40 ++++++++++++++++++++++++++++++++++++ tests/utilities/test_i18n.py | 10 +++++++++ 4 files changed, 70 insertions(+), 4 deletions(-) create mode 100644 tests/crew_language_test.py diff --git a/src/crewai/crew.py b/src/crewai/crew.py index b5f3e3ff5..b941d1950 100644 --- a/src/crewai/crew.py +++ b/src/crewai/crew.py @@ -191,6 +191,14 @@ class Crew(BaseModel): default=None, description="Path to the prompt json file to be used for the crew.", ) + language: Optional[str] = Field( + default="en", + description="Language used for the crew, defaults to English.", + ) + language_file: Optional[str] = Field( + default=None, + description="Path to the language file to be used for the crew.", + ) output_log_file: Optional[Union[bool, str]] = Field( default=None, description="Path to the log file to be saved", @@ -609,7 +617,7 @@ class Crew(BaseModel): self._interpolate_inputs(inputs) self._set_tasks_callbacks() - i18n = I18N(prompt_file=self.prompt_file) + i18n = I18N(prompt_file=self.prompt_file, language=self.language) for agent in self.agents: agent.i18n = i18n @@ -751,7 +759,7 @@ class Crew(BaseModel): return self._execute_tasks(self.tasks) def _create_manager_agent(self): - i18n = I18N(prompt_file=self.prompt_file) + i18n = I18N(prompt_file=self.prompt_file, language=self.language) if self.manager_agent is not None: self.manager_agent.allow_delegation = True manager = self.manager_agent diff --git a/src/crewai/utilities/i18n.py b/src/crewai/utilities/i18n.py index f2540e455..3ca8933a1 100644 --- a/src/crewai/utilities/i18n.py +++ b/src/crewai/utilities/i18n.py @@ -13,6 +13,10 @@ class I18N(BaseModel): default=None, description="Path to the prompt_file file to load", ) + language: Optional[str] = Field( + default="en", + description="Language to use for translations", + ) @model_validator(mode="after") def load_prompts(self) -> "I18N": @@ -23,8 +27,12 @@ class I18N(BaseModel): self._prompts = json.load(f) else: dir_path = os.path.dirname(os.path.realpath(__file__)) - prompts_path = os.path.join(dir_path, "../translations/en.json") - + lang = self.language or "en" + prompts_path = os.path.join(dir_path, f"../translations/{lang}.json") + + if not os.path.exists(prompts_path): + prompts_path = os.path.join(dir_path, "../translations/en.json") + with open(prompts_path, "r", encoding="utf-8") as f: self._prompts = json.load(f) except FileNotFoundError: diff --git a/tests/crew_language_test.py b/tests/crew_language_test.py new file mode 100644 index 000000000..4366543ff --- /dev/null +++ b/tests/crew_language_test.py @@ -0,0 +1,40 @@ +import pytest +from unittest.mock import patch + +from crewai import Crew, Agent, Process, Task +from crewai.utilities.i18n import I18N + + +def test_crew_with_language(): + i18n = I18N(language="en") + + agent = Agent( + role="Test Agent", + goal="Test Goal", + backstory="Test Backstory", + verbose=True + ) + + task = Task( + description="Test Task", + expected_output="Test Output", + agent=agent + ) + + with patch('crewai.crew.I18N') as mock_i18n: + mock_i18n.return_value = i18n + + crew = Crew( + agents=[agent], + tasks=[task], + process=Process.sequential, + verbose=True, + language="fr" # Use French as an example + ) + + with patch.object(crew, '_run_sequential_process'): + with patch.object(crew, '_set_tasks_callbacks'): + with patch('crewai.agent.Agent.create_agent_executor'): + crew.kickoff() + + mock_i18n.assert_called_with(prompt_file=None, language="fr") diff --git a/tests/utilities/test_i18n.py b/tests/utilities/test_i18n.py index 8627b0bec..6887fb75e 100644 --- a/tests/utilities/test_i18n.py +++ b/tests/utilities/test_i18n.py @@ -42,3 +42,13 @@ def test_prompt_file(): i18n.load_prompts() assert isinstance(i18n.retrieve("slices", "role_playing"), str) assert i18n.retrieve("slices", "role_playing") == "Lorem ipsum dolor sit amet" + + +def test_language_parameter(): + i18n = I18N(language="en") + i18n.load_prompts() + assert isinstance(i18n.slice("role_playing"), str) + + i18n = I18N(language="nonexistent") + i18n.load_prompts() + assert isinstance(i18n.slice("role_playing"), str)