Tinygettext - A simple gettext replacement that works directly on .po files

Overview

tinygettext

tinygettext is a minimal replacement for gettext written in C++. It can read .po files directly and doesn't need .mo files generated from .po. It also can read the .po files from arbitrary locations, so it's better suited for non-Unix systems and situations in which one wants to store or distribute .po files separately from the software itself. It is licensed under zlib license.

The latest version can be found at:

Detecting the locale setting

Different operating systems store the default locale in different places; a portable way to find it is provided by FindLocale:

Projects using this library

Comments
  • Fix Arabic plural equation

    Fix Arabic plural equation

    Fix the plural equation. We changed the formula to a new one years ago!

    Source: http://localization-guide.readthedocs.org/en/latest/l10n/pluralforms.html

    opened by SafaAlfulaij 3
  • Some patches from SuperTuxKart

    Some patches from SuperTuxKart

    Hi,

    we have included tinygettext in supertuxkart, and have applied a few minor patches over time. A full list can be found on our github: https://github.com/supertuxkart/stk-code/commits/master/src/tinygettext

    But here in short the somewhat important and portable ones: Fix missing include for some newer compilers:

    --- a/src/tinygettext/language.cpp
    +++ b/src/tinygettext/language.cpp
    @@ -20,6 +20,7 @@
     #include <map>
     #include <assert.h>
     #include <vector>
    +#include <algorithm>
    
     namespace tinygettext {
    

    Change pt-BR name to be more accurate:

    --- a/src/tinygettext/language.cpp
    +++ b/src/tinygettext/language.cpp
    @@ -213,7 +213,7 @@ static const LanguageSpec languages[] = {
       { "pl", "PL", 0, "Polish (Poland)"             },
       { "ps", 0,    0, "Pashto"                      },
       { "pt", 0,    0, "Portuguese"                  },
    -  { "pt", "BR", 0, "Brazilian"                   },
    +  { "pt", "BR", 0, "Portuguese (Brazil)"         },
       { "pt", "PT", 0, "Portuguese (Portugal)"       },
       { "qu", 0,    0, "Quechua"                     },
       { "rm", 0,    0, "Rhaeto-Romance"              },
    

    Fix 64 bit compilation:

    --- a/src/tinygettext/po_parser.cpp
    +++ b/src/tinygettext/po_parser.cpp
    @@ -207,7 +207,7 @@ next:
             if (pedantic)
               warning("leading whitespace before string");
    
    -      get_string_line(out, i);
    +      get_string_line(out, (unsigned int) i);
           goto next;
         }
         else if (isspace(current_line[i]))
    @@ -245,7 +245,7 @@ POParser::parse_header(const std::string& header)
           if (has_prefix(line, "Content-Type:"))
           {
             // from_charset = line.substr(len);
    -        unsigned int len = strlen("Content-Type: text/plain; charset=");
    +        unsigned int len = (unsigned int) strlen("Content-Type: text/plain; charset=");
             if (line.compare(0, len, "Content-Type: text/plain; charset=") == 0)
             {
               from_charset = line.substr(len);
    

    tinygettext const fix

    This moves ~8kb of writable data to RO, and improves optimization. There is no need for the initial array to be writable anyhow.

    --- a/src/tinygettext/language.cpp
    +++ b/src/tinygettext/language.cpp
    @@ -39,7 +39,7 @@ struct LanguageSpec {
    
     /** Language Definitions */
     //*{
    -LanguageSpec languages[] = {
    +static const LanguageSpec languages[] = {
       { "aa", 0,    0, "Afar"                        },
       { "af", 0,    0, "Afrikaans"                   },
       { "af", "ZA", 0, "Afrikaans (South Africa)"    },
    @@ -364,7 +364,7 @@ resolve_language_alias(const std::string& name)
     Language
     Language::from_spec(const std::string& language, const std::string& country, const std::string& modifier)
     {
    -  static std::map<std::string, std::vector<LanguageSpec*> > language_map;
    +  static std::map<std::string, std::vector<const LanguageSpec*> > language_map;
    
       if (language_map.empty())
       { // Init language_map
    @@ -372,10 +372,10 @@ Language::from_spec(const std::string& language, const std::string& country, con
           language_map[languages[i].language].push_back(&languages[i]);
       }
    
    -  std::map<std::string, std::vector<LanguageSpec*> >::iterator i = language_map.find(language);
    +  std::map<std::string, std::vector<const LanguageSpec*> >::iterator i = language_map.find(language);
       if (i != language_map.end())
       {
    -    std::vector<LanguageSpec*>& lst = i->second;
    +    std::vector<const LanguageSpec*>& lst = i->second;
    
         LanguageSpec tmpspec;
         tmpspec.language = language.c_str();
    @@ -383,9 +383,9 @@ Language::from_spec(const std::string& language, const std::string& country, con
         tmpspec.modifier = modifier.c_str();
         Language tmplang(&tmpspec);
    
    -    LanguageSpec* best_match = 0;
    +    const LanguageSpec* best_match = 0;
         int best_match_score = 0;
    -    for(std::vector<LanguageSpec*>::iterator j = lst.begin(); j != lst.end(); ++j)
    +    for(std::vector<const LanguageSpec*>::iterator j = lst.begin(); j != lst.end(); ++j)
         { // Search for the language that best matches the given spec, value country more then modifier
           int score = Language::match(Language(*j), tmplang);
    
    @@ -445,7 +445,7 @@ Language::from_env(const std::string& env)
       return from_spec(language, country, modifier);
     }
    
    -Language::Language(LanguageSpec* language_spec_)
    +Language::Language(const LanguageSpec* language_spec_)
       : language_spec(language_spec_)
     {
     }
    diff --git a/src/tinygettext/language.hpp b/src/tinygettext/language.hpp
    index bd4a3ea..0ab2f32 100644
    --- a/src/tinygettext/language.hpp
    +++ b/src/tinygettext/language.hpp
    @@ -28,9 +28,9 @@ struct LanguageSpec;
     class Language
     {
     private:
    -  LanguageSpec* language_spec;
    +  const LanguageSpec* language_spec;
    
    -  Language(LanguageSpec* language_spec);
    +  Language(const LanguageSpec* language_spec);
    
     public:
       /** Create a language from language and country code:
    
    opened by hiker 2
  • .po files are not found on Unix systems

    .po files are not found on Unix systems

    stem() results in locale/da.po cecomming da which fails the .po sufix check.

    https://github.com/tinygettext/tinygettext/blob/0c31494e2f66686cddb4c399017bb2993ff3a4bb/src/unix_file_system.cpp#L38

    A workaround is to have an empty file called da.po.po

    https://en.cppreference.com/w/cpp/filesystem/path/stem

    opened by AJenbo 1
  • Disambiguate iconv calls to avoid compilation issues on BSD.

    Disambiguate iconv calls to avoid compilation issues on BSD.

    Based on a pull request on our game (https://github.com/abunchofhacks/Epicinium/pull/4):

    DragonFly, FreeBSD, NetBSD (but not OpenBSD) have iconv* support from Citrus Project. What causes ambiguity is system iconv_t defined as a struct pointer instead a void pointer.

    Clang error
    $ c++ --version
    FreeBSD clang version 11.0.0 ([email protected]:llvm/llvm-project.git llvmorg-11.0.0-0-g176249bd673)
    Target: x86_64-unknown-freebsd13.0
    Thread model: posix
    InstalledDir: /usr/bin
    
    $ CPATH=/usr/local/include gmake .obj/libs/tinygettext/iconv.o
    c++ -std=c++17 -MT .obj/libs/tinygettext/iconv.o -MMD -MP -MF .dep/libs/tinygettext/iconv.Td -O3 -s -I ./ -I libs -I libs/SDL2 -o .obj/libs/tinygettext/iconv.o -c libs/tinygettext/iconv.cpp
    libs/tinygettext/iconv.cpp:50:5: error: call to 'iconv_close' is ambiguous
        iconv_close(cd);
        ^~~~~~~~~~~
    /usr/include/iconv.h:61:5: note: candidate function
    int     iconv_close(iconv_t);
            ^
    libs/tinygettext/iconv.hpp:69:12: note: candidate function
    inline int iconv_close(iconv_t cd)
               ^
    libs/tinygettext/iconv.cpp:57:5: error: call to 'iconv_close' is ambiguous
        iconv_close(cd);
        ^~~~~~~~~~~
    /usr/include/iconv.h:61:5: note: candidate function
    int     iconv_close(iconv_t);
            ^
    libs/tinygettext/iconv.hpp:69:12: note: candidate function
    inline int iconv_close(iconv_t cd)
               ^
    libs/tinygettext/iconv.cpp:119:9: error: call to 'iconv' is ambiguous
            iconv(cd, nullptr, nullptr, nullptr, nullptr); // reset state
            ^~~~~
    /usr/include/iconv.h:58:8: note: candidate function
    size_t  iconv(iconv_t, char ** __restrict,
            ^
    libs/tinygettext/iconv.hpp:58:15: note: candidate function
    inline size_t iconv(iconv_t cd,
                  ^
    
    GCC error
    $ g++11 --version
    g++11 (FreeBSD Ports Collection) 11.0.0 20201108 (experimental)
    Copyright (C) 2020 Free Software Foundation, Inc.
    This is free software; see the source for copying conditions.  There is NO
    warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
    
    $ CXX=g++11 gmake .obj/libs/tinygettext/iconv.o                                                               3& iconv γ /tmp/epicinium
    g++11  -std=c++17 -MT .obj/libs/tinygettext/iconv.o -MMD -MP -MF .dep/libs/tinygettext/iconv.Td -O3 -s  -I ./  -I libs -I libs/SDL2 -o .obj/libs/tinygettext/iconv.o -c libs/tinygettext/iconv.cpp
    libs/tinygettext/iconv.cpp: In destructor 'tinygettext::IConv::~IConv()':
    libs/tinygettext/iconv.cpp:50:19: error: call of overloaded 'iconv_close(__tag_iconv_t*&)' is ambiguous
       50 |     iconv_close(cd);
          |                   ^
    In file included from libs/tinygettext/iconv.cpp:28:
    libs/tinygettext/iconv.hpp:69:12: note: candidate: 'int tinygettext::iconv_close(tinygettext::iconv_t)'
       69 | inline int iconv_close(iconv_t cd)
          |            ^~~~~~~~~~~
    In file included from libs/tinygettext/iconv.hpp:28,
                     from libs/tinygettext/iconv.cpp:28:
    /usr/include/iconv.h:61:9: note: candidate: 'int iconv_close(iconv_t)'
       61 | int     iconv_close(iconv_t);
          |         ^~~~~~~~~~~
    libs/tinygettext/iconv.cpp: In member function 'void tinygettext::IConv::set_charsets(const string&, const string&)':
    libs/tinygettext/iconv.cpp:57:19: error: call of overloaded 'iconv_close(__tag_iconv_t*&)' is ambiguous
       57 |     iconv_close(cd);
          |                   ^
    In file included from libs/tinygettext/iconv.cpp:28:
    libs/tinygettext/iconv.hpp:69:12: note: candidate: 'int tinygettext::iconv_close(tinygettext::iconv_t)'
       69 | inline int iconv_close(iconv_t cd)
          |            ^~~~~~~~~~~
    In file included from libs/tinygettext/iconv.hpp:28,
                     from libs/tinygettext/iconv.cpp:28:
    /usr/include/iconv.h:61:9: note: candidate: 'int iconv_close(iconv_t)'
       61 | int     iconv_close(iconv_t);
          |         ^~~~~~~~~~~
    libs/tinygettext/iconv.cpp: In member function 'std::string tinygettext::IConv::convert(const string&)':
    libs/tinygettext/iconv.cpp:119:53: error: call of overloaded 'iconv(__tag_iconv_t*&, std::nullptr_t, std::nullptr_t, std::nullptr_t, std::nullptr_t)' is ambiguous
      119 |         iconv(cd, nullptr, nullptr, nullptr, nullptr); // reset state
          |                                                     ^
    In file included from libs/tinygettext/iconv.cpp:28:
    libs/tinygettext/iconv.hpp:58:15: note: candidate: 'size_t tinygettext::iconv(tinygettext::iconv_t, const char**, size_t*, char**, size_t*)'
       58 | inline size_t iconv(iconv_t cd,
          |               ^~~~~
    In file included from libs/tinygettext/iconv.hpp:28,
                     from libs/tinygettext/iconv.cpp:28:
    /usr/include/iconv.h:58:9: note: candidate: 'size_t iconv(iconv_t, char**, size_t*, char**, size_t*)'
       58 | size_t  iconv(iconv_t, char ** __restrict,
          |         ^~~~~
    
    opened by SLiV9 0
  • UnixFileSystem trims extensions, causing no PO files to be found

    UnixFileSystem trims extensions, causing no PO files to be found

    I think I found a bug caused by a recent rewrite.

    In commit 9bb55f3d7652e6097abcf248748509fb998cb52f, an older implementation of UnixFileSystem was replaced with one based on std::filesystem. However p.path().stem() is used instead of p.path().filename(), which means UnixFileSystem::open_directory() returns a vector of stems instead of a vector of filenames. For example it returns "en_US" if there is a file named "en_US.po". This causes the DictionaryManager to ignore all of the files in the directory, because it thinks there are no files ending on "po".

    If it helps: this was when I cloned commit 0c31494e2f66686cddb4c399017bb2993ff3a4bb. ~~My current workaround is checking out commit e406e999b0c37c06cf1ec429b22669c40b16bf4f instead.~~ Replacing stem() with filename() fixed this.

    opened by SLiV9 0
  • -Wabi won't warn about anything

    -Wabi won't warn about anything

    cc1plus: warning: -Wabi won't warn about anything [-Wabi]
    cc1plus: note: -Wabi warns about differences from the most up-to-date ABI, which is also used by default
    cc1plus: note: use e.g. -Wabi=11 to warn about changes from GCC 7
    

    Not sure what was the intention behind adding -Wabi to the list, but it should probably either be dropped or updated to actually do something :)

    opened by dos1 0
  • Improved collision logging

    Improved collision logging

    Currently collisions for plural strings do not tell the user what actually conflicts, so first check if something actually conflicts and if yes log all plurals for the current and the new translation.

    opened by leper 0
  • Changes from 0 A.D.

    Changes from 0 A.D.

    See http://trac.wildfiregames.com/changeset/15179/ and http://trac.wildfiregames.com/ticket/2575 for the first commit.

    http://trac.wildfiregames.com/changeset/15493/ for the second.

    opened by leper 0
  • Compilation failure on Win10 VS2017

    Compilation failure on Win10 VS2017

    po_parser.cpp

    code with truncation error: // skip UTF-8 intro that some text editors produce // see http://en.wikipedia.org/wiki/Byte-order_mark if (current_line.size() >= 3 && current_line[0] == static_cast(0xef) && current_line[1] == static_cast(0xbb) && current_line[2] == static_cast(0xbf)) { current_line = current_line.substr(3); }

    can be corrected so: // skip UTF-8 intro that some text editors produce // see http://en.wikipedia.org/wiki/Byte-order_mark if (current_line.size() >= 3 && current_line[0] == '\xEF' && current_line[1] == '\xBB' && current_line[2] == '\xBF') { current_line = current_line.substr(3); }

    opened by RKGekk 0
  • Compilation failure on MacOS 10.13

    Compilation failure on MacOS 10.13

    It seems macOS doesn't define filesystem prior to macOS 10.15

    builderr-debug-macos.txt
    ../../../source/third_party/tinygettext/src/unix_file_system.cpp:24:10: fatal error: 'filesystem' file not found
    #include <filesystem>
             ^~~~~~~~~~~~
    1 error generated.
    make[1]: *** [obj/tinygettext_Debug/unix_file_system.o] Error 1
    make[1]: *** Waiting for unfinished jobs....
    make: *** [tinygettext] Error 2
    

    According to https://stackoverflow.com/questions/42633477/macos-clang-c17-filesystem-header-not-found we need to include <experimental/filesystem>for those OSes

    so maybe a check like

    // Untested
    #if defined(__APPLE__) && defined(__clang_major__) && __clang_major__ < 11
    #include <experimental/filesystem>
    #else
    #include <filesystem>
    #endif
    

    Not sure what your requirements are for this library but I understand that os might be too old, feel free to close this issue then.

    opened by StanleySweet 1
  • Plural forms expression parser

    Plural forms expression parser

    Hello, I have implemented an expression parser for plural forms, which will fix #21 .

    After I have implemented this, I also checked the official GNU gettext implementation, they also have an expression parser for plural forms (event for the default one n!=1).

    opened by acmepjz 1
  • It looks like that a plural form description is missing a semicolon

    It looks like that a plural form description is missing a semicolon

    It looks like that the last plural form description in the following file is missing an ending semicolon, compare to other plural form descriptions in the same file before:

    https://github.com/tinygettext/tinygettext/blob/93ceb742f6a4160e6ca0668881db14338be9b90a/src/plural_forms.cpp#L73

    Is it correct?

    opened by acmepjz 0
  • Implement a simple expression parser in PluralForms

    Implement a simple expression parser in PluralForms

    It looks like that in PluralForms class the input plural forms description is only simply compare with a predefined list. Is it feasible to implement a simple expression parser to handle plural forms outside the predefined list?

    If yes, I'd like to implement one and submit a pull request later.

    opened by acmepjz 2
Owner
null
A simple "no frills" drop-in replacement PCB for the KBDfans 67mkII / 67lite

67mk_E A simple "no frills" drop-in replacement PCB for the KBDfans 67mkII / 67lite KiCAD PCB files Gerbers for PCB production JLCPCB BOM JLCPCB CPL V

null 24 Dec 18, 2022
Assembly HellGate implementation that directly calls Windows System Calls and displays the PPID of the explorer.exe process

Custom HellsGate Implementation Assembly HellGate implementation that directly calls Windows System Calls and displays the PPID of the explorer.exe pr

Bobby Cooke 90 Oct 18, 2022
An implementation of a Windows loader that can load dynamic-linked libraries (DLLs) directly from memory

memory-module-loader memory-module-loader is an implementation of a Windows loader that can load dynamic-link libraries (DLLs) directly from memory. T

SCYTHE 118 Nov 21, 2022
Galaxy simulation that runs directly into your terminal !

ASCII-galaxy-simulation (Work in progress) Current result : Two galaxies colliding Goal : Galaxy with black hole (Should make the galaxies more stable

Célian Riboulet 7 Nov 26, 2022
PyAerotech: An Opensource Python Library or interfacing directly with the Aerotech A3200 Controlle

PyAerotech: An Opensource Python Library or interfacing directly with the Aerotech A3200 Controller pyAerotech is an additional Opensource Python libr

Dr Luke Parry 3 Aug 22, 2022
DO NOT DIRECTLY COPY&SUBMIT THANK YOU

GDUT Programming Project (2021 fall semester) Sorry for no annotations because my friends ask me for uploading this and I have no time to write them.

null 2 Jun 16, 2022
The package allows to use H3 library directly in your Flutter application

The package allows to use H3 library directly in your Flutter application

Ilya Beregovskiy 12 Dec 21, 2022
Anotter USB temperature logger that can record up to four channels with thermocouple or NTCs connected via CDC directly or SCPI to USB.

temperature-logger Anotter USB temperature logger that can record up to four channels with thermocouple or NTCs connected via CDC directly or SCPI to

Jana Marie Hemsing 50 Nov 24, 2022
Add virtual monitors to your windows 10 device! Works with Oculus software, obs, and any desktop sharing software

License MIT and CC0 or Public Domain, whichever is least restrictive -- Use it AS IS - NO IMPLICIT OR EXPLICIT warranty This may break your computer,

Rashi Abramson 230 Jan 6, 2023
Tutorials on how the UEFI works

Step by Step Tutorials on how to use the UEFI for OS Development from scratch THIS IS WINDOWS BASED TUTS, BUT CODE SHOULD WORK IN LINUX AND MAC. NOTE

ThatOSDev 7 Dec 28, 2022
This repository is to explain how the SN74HC595 register works

Register_SN74HC595 This repository is to explain how the SN74HC595 register works Aujourd’hui on va apprendre à comment augmenter le nombre de sortie

mugiwarra229 5 Jun 8, 2021
Obfuscate calls to imports by patching in stubs. ICO works on both X86 and X64 binaries.

ICO adds a new section into the image, then begins building stubs for each import that uses a extremely basic routine to decrypt an RVA and places them into the section.

null 43 Dec 15, 2022
Unix pager (with very rich functionality) designed for work with tables. Designed for PostgreSQL, but MySQL is supported too. Works well with pgcli too. Can be used as CSV or TSV viewer too. It supports searching, selecting rows, columns, or block and export selected area to clipboard.

Unix pager (with very rich functionality) designed for work with tables. Designed for PostgreSQL, but MySQL is supported too. Works well with pgcli too. Can be used as CSV or TSV viewer too. It supports searching, selecting rows, columns, or block and export selected area to clipboard.

Pavel Stehule 1.9k Jan 4, 2023
kbuild is a build tool that works "like make" targetted at kernel/os development

kbuild : a kernel (and os) builder kbuild is a build tool that works "like make" targetted at kernel/os development Installing and building kbuild kbu

Valentin HAUDIQUET 1 Dec 11, 2021
hacktober fest 2021 repo, push any code which works for dsa

Hacktoberfest 2021 ✨ This repo contains collection of all competitive programming algorithms. I will be happy to accept any contributions during Hackt

Utkarsh Gupta 1 Oct 30, 2021
[PS3] Bo1 Mod Menu Jo-Milk's Playground V2... I never finished this project what a shame... works on HEN

-PS3-Bo1-Mod-Menu-Jo-Milk-s-Playground-V2 [PS3] Bo1 Mod Menu Jo-Milk's Playground V2... I never finished this project what a shame... works on HEN Ple

Jo-Milk 5 Oct 9, 2022
My_Shell is a user-defined interactive shell written in C that works similar to the original shell in linux

MY_SHELL Overview My_Shell is a user-defined interactive shell written in C that works similar to the original shell and it can execeute many of the l

Greeshma 1 Nov 22, 2021
42 Kocaeli Successed Piscine Works

?? Ödev tablosu : Project Tr Eng Solutions BSQ tr eng Full Problem Shell00 tr eng 10 Problems Shell01 tr eng 6 Problems C00 tr eng 8 Problems C01 tr e

Ahmet ERYILMAZ 15 Oct 12, 2022
Repository contains 1372 group lab works

Осенний курс по дисциплине "Программирование" 2021 Правила работы с репозиторием Для начала работы каждый студент делает форк (fork) репозитория на св

null 5 Mar 26, 2022