Justasic / flapp

Language translation and formatting library for Python

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Flapp

Flapp is the ultimate translation system for your project. It is intended to correctly translate all strings in a program to any language without needing to add multiple strings for the same sentence just to make something plural. This also allows for locale-specific dates and times, pluralization, and potentially even conditionals which enables advanced formatting!

Localization is nothing more than a string lookup system from a set of files which you can specify the system for looking up those file names. The translate function takes a string which contains a sequence of filters inside the translatable string. These filters are similar to Django template filters that allow for flexible string generation for translation.

Syntax for all filters is as follows: {VARIABLE|filter:filter "arguments"} , the variable names are case insensitive.

Setup

python setup.py install

Usage

Assume there is a file translations.en_US.yml in the folder locales which exists with the content:

user:
    hello-message: "Hello, {USERNAME|title}! It is {NOW|date:\"D d M Y\"}!"

and translations.ru_RU.yml in the same folder:

user:
    hello-message: "Привет, {USERNAME|title}! Сегодня {NOW|date:\"D d M Y\"}!"

To format/translate a string:

>> from flapp import Flapp
>> from datetime import datetime
>> translator = Flapp("/path/to/locales", file_pattern="translations.{locale}.yml", default="en_US")
>> translator.translate("user.hello-message", username="flapper", now=datetime.now())
Hello, Flapper! It is Wed 09 Jan 2008!
>> translator.translate("user.hello-message", "ru_RU", username="flapper", now=datetime.now())
Привет, Flapper! Сегодня Wed 09 Jan 2008!

The translate function takes a "node" which represents the path to the string. See Loading other formats below.

The second argument to translate is used to specify a locale different from the default locale, this locale is used to find and load the locale file if it is not already loaded.

Built-in filters

There are some basic filters that come included:

filter Description Arguments Default
pluralize Add text if a number is greater than 1 comma separated list based on count "s" if plural
yesno Convert a boolean value to the language's boolean representation comma separated pair in place of "no,yes" "yes" or "no"
datetime Format the variable as a datetime string strftime-compatible format string datetime default formatt
cut Removes text from a variable quoted string of text to remove N/A
empty_if_false Returns an empty string if the variable evaluates to False value returned if True N/A
empty_if_true Returns an empty string if the variable evaluates to True value returned if False N/A
default_if_none Returns a default value if the variable is False/None default value N/A
lower Convert the variable to all lowercase N/A N/A
upper Convert the variable to all uppercase N/A N/A
title Convert the variable to titlecase (capitalize the first letter of every word) N/A N/A
join Join a list together with a deliminator deliminator string ", "

You can also add your own filters if you need to do some special formatting. The variable to be formatted and the filter's arguments are passed as strings to the bound function. An example:

user:
    hello-message: "Hello {WHO|memecase}!"
>> from flapp import Flapp
>> from random import choice
>> translator = Flapp("/path/to/locales", identifier="translations.{locale}.yml", default="en_US")
>> def memecase(locale: str, variable, argument: str):
>>    return ''.join(choice((str.upper, str.lower))(c) for c in str(variable))
>> translator.add_filter('memecase', memecase)
>> translator.translate("user.hello-message", who="World")
Hello WoRLd!

Note that the type of variable in the memecase function is undefined as it leaves it up to the memecase function to return a correctly formatted string. Any data returned from the function will be cast as a string regardless.

Loading other formats

While Yaml and JSON files are supported by default, you can load the same data from other sources by calling add_locale with a dictionary to that of what json.loads() would return. The node can be deliniated by a period (.) and each part of the node is then used as the key for the recursive dictionaries. An example from the above example code effectively does:

>> yamldata['user']['hello-message']
Hello, {USERNAME|title}! It is {NOW|date:\"D d M Y\"}!

You can verify if a locale is loaded using locale_loaded("en_GB") and you can unload loaded locales with remove_locale("en_GB") (replacing "en_GB" with the locale format you're using)

You can also extend the file loader system by adding a callable with add_loader or removing it with remove_loader. An example loader is the yaml file loader:

def _yaml_loader(p: Path, locale: str, fl: Flapp):
		try:
			import yaml
			if p.suffix in [".yaml", ".yml"]:
				with p.open() as fp:
					fl.add_locale(locale, fp)
		except ImportError:
			pass

then call add_loader("yaml", _yaml_loader) to add it. The string argument is just an identfier for remove_loader calls later.


License

Copyright 2021 Justin Crawford Justin@stacksmash.net

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

About

Language translation and formatting library for Python


Languages

Language:Python 100.0%