Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding multi language support #14

Merged
merged 11 commits into from
Feb 18, 2024
Merged
5 changes: 4 additions & 1 deletion .github/workflows/pull_request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,14 @@ jobs:
with:
fetch-depth: 1

- name: Installing gettext
run: sudo apt-get install gettext

- name: Installing the project
run: make docker/install

- name: Running Lint
run: make docker/lint

- name: Running tests
run: make docker/test
run: make docker/test
8 changes: 6 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ MAIN_ENTRYPOINT="src/bot.py"
# COMMANDS TO RUN LOCALLY
################################

local/install: generate-default-env-file
local/install: generate-default-env-file generate-mo-files
poetry install

local/tests:
Expand All @@ -32,7 +32,7 @@ local/run:
# COMMANDS TO RUN USING DOCKER (RECOMMENDED)
############################################

docker/install: generate-default-env-file
docker/install: generate-default-env-file generate-mo-files
docker-compose build ${APP_NAME}

docker/up:
Expand Down Expand Up @@ -69,3 +69,7 @@ docker/image/push:

generate-default-env-file:
@if [ ! -f .env ]; then cp env.template .env; fi;

generate-mo-files:
msgfmt -o src/locales/en/LC_MESSAGES/base.mo src/locales/en/LC_MESSAGES/base.po
msgfmt -o src/locales/pt_BR/LC_MESSAGES/base.mo src/locales/pt_BR/LC_MESSAGES/base.po
35 changes: 31 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

A simple slack bot that analyzes messages sent on channels and warns about possible sensitive data from someone, such as a social security number, for example.

## How bot works on slack workspace

![Bot working](.docs/print_bot_working.png)

## Technology and Resources

- [Python 3.11](https://www.python.org/downloads/release/python-3110/) - **pre-requisite**
Expand All @@ -10,6 +14,9 @@ A simple slack bot that analyzes messages sent on channels and warns about possi
- [Poetry](https://python-poetry.org/) - **pre-requisite**
- [Ruff](https://github.com/astral-sh/ruff)
- [Slack Bolt](https://pypi.org/project/slack-bolt/)
- [i18n](https://docs.python.org/3/library/i18n.html)



*Please pay attention on **pre-requisites** resources that you must install/configure.*

Expand All @@ -29,10 +36,6 @@ im:read

Follow this [guide](https://api.slack.com/tutorials/tracks/getting-a-token) to generate the tokens.

## How bot works on slack workspace

![Bot working](.docs/print_bot_working.png)

## How to install, run and test

### Environment variables
Expand All @@ -41,6 +44,7 @@ Variable | Description | Available Values | Default Value | Required
--- | --- | --- | --- | ---
ENV | The application enviroment | `dev / test / qa / prod` | `dev` | Yes
PYTHONPATH | Provides guidance to the Python interpreter about where to find libraries and applications | [ref](https://docs.python.org/3/using/cmdline.html#envvar-PYTHONPATH) | `.` | Yes
LANGUAGE | The bot language | `en | pt_BR` | `pt_BR` | Yes
SLACK_BOT_TOKEN | The slack bot token | `a valid token` | `-` | Yes
SLACK_APP_TOKEN | The slack app token | `a valid token` | `-` | Yes

Expand All @@ -60,6 +64,29 @@ push image | `make docker/image/push` | - | to push the docker image

*Please, check all available commands in the [Makefile](Makefile) for more information*.

## Multi Language

The Bot supports multiple languages using [i18n](https://docs.python.org/3/library/i18n.html) pattern.

Locale file structure:
```
├─ src
│  ├─ locales
│  │  └─ en
│  │   └─ LC_MESSAGES
│  │   └─ base.po
│  │  └─ pt_BR
│  │   └─ LC_MESSAGES
│  │   └─ base.po
```

### How to add a new language

1) Create a new folder in `src/locales` with the new language;
2) Create a new `base.po` file inside this folder (you just can copy from another language);
3) Translate all the messages;
4) Generate the `mo` files using the command `make generate-mo-files`

## Logging

This project uses a simple way to configure the log with [logging.conf](logging.conf) to show the logs on the container output console.
Expand Down
1 change: 1 addition & 0 deletions env.template
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
ENV=dev
PYTHONPATH=.
LANGUAGE=pt_BR
SLACK_BOT_TOKEN=
SLACK_APP_TOKEN=
20 changes: 20 additions & 0 deletions src/config/language.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from gettext import GNUTranslations, translation
from os import getenv


class Language:
__slots__ = ['gnu_translations']
gnu_translations: GNUTranslations

def __init__(self,
domain: str = 'base',
locale_dir: str = './src/locales',
fallback: bool = True,
lang: str = getenv('LANGUAGE', 'pt_BR')):

self.gnu_translations = translation(domain, locale_dir, fallback=fallback, languages=[lang])

def translate(self, text: str) -> str:
return self.gnu_translations.gettext(text)

language = Language()
5 changes: 3 additions & 2 deletions src/listeners/messages/regex_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from slack_bolt import App

from src.messages.constants import DEFAULT_WARNING_MESSAGE
from src.config.language import language
from src.rules.pattern import pattern

logger = getLogger(__name__)
Expand All @@ -15,6 +15,7 @@ async def register(app: App):
async def regex_message_callback(message, say):
try:
user = message['user']
await say(text=DEFAULT_WARNING_MESSAGE.format(name=f'<@{user}>'), thread_ts=message.get('ts'))
text = f'{language.translate("Hello")} <@{user}>, {language.translate("Do not send sensitive info")}'
await say(text=text, thread_ts=message.get('ts'))
except Exception as e:
logger.error(e)
5 changes: 5 additions & 0 deletions src/locales/en/LC_MESSAGES/base.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
msgid "Hello"
msgstr "Hello"

msgid "Do not send sensitive info"
msgstr "please do not send social security number, email, phone number (or any other sensitive data) on public channels here through slack"
10 changes: 10 additions & 0 deletions src/locales/pt_BR/LC_MESSAGES/base.po
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
msgid ""
msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Language: pt_BR\n"

msgid "Hello"
msgstr "Olá"

msgid "Do not send sensitive info"
msgstr "por favor não envie CPF, email, telefone (ou qualquer outro dado sensível) em canais públicos aqui pelo slack"
3 changes: 0 additions & 3 deletions src/messages/constants.py

This file was deleted.

17 changes: 17 additions & 0 deletions tests/config/test_language.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from unittest import TestCase

from src.config.language import Language


class LanguageTest(TestCase):
def test_translate_hello_message_to_pt_br(self):
language = Language(lang='pt_BR')
self.assertEqual(language.translate('Hello'), 'Olá')

def test_translate_hello_message_to_en(self):
language = Language(lang='en')
self.assertEqual(language.translate('Hello'), 'Hello')

def test_translate_hello_message_to_default_when_language_is_not_supported(self):
language = Language(lang='foo')
self.assertEqual(language.translate('Hello'), 'Hello')
Loading