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 23 Nov 2, 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 11 Nov 16, 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
The Sensor Watch is a board replacement for the classic Casio F-91W wristwatch.

The Sensor Watch is a board replacement for the classic Casio F-91W wristwatch.

null 648 Nov 28, 2022
Commodore 64 VIC-II 6567/6569 Replacement Project

This is a WIP. Beta testing is underway on hardware. Check back later for updates. VIC-II Kawari What is VIC-II Kawari? VIC-II Kawari is a hardware re

null 46 Nov 29, 2022
crashmon - A LLDB Based replacement for CrashWrangler

crashmon crashmon - A CrashWrangler replacement based on LLDB Crashmon, same as CrashWrangelr, is a LLDB wrapper together with Lisa.py that can be use

Chaithu 33 Nov 9, 2022
Amiga 1200 keyboard MPU drop-in replacement pcb

A1200_keyb_MPU Amiga 1200 keyboard MPU drop-in replacement pcb As the 68HC05 (p/n 391508-01) used in the Amiga 1200 is getting to be very expensive, I

Oleg Mishin 19 Nov 26, 2022
ASUS services replacement for Zephyrus G14 laptops

G14ControlPP ASUS services replacement for Zephyrus G14 laptops Introduction Initially, main goal was to bring back PgUp/PgDown/Home/End keys function

null 13 Oct 25, 2022
An open-source replacement for Windows UAC

Custom UAC What is it It is an open source replacement of UAC. It was a successor of my previous project UAC Renderer. As the functionalities and usag

null 3 Mar 6, 2022
mold is a faster drop-in replacement for existing Unix linkers

mold: A Modern Linker mold is a faster drop-in replacement for existing Unix linkers. It is several times faster than LLVM lld linker, the second-fast

Rui Ueyama 9.6k Nov 27, 2022
Ccd - Edge first cd replacement tool for Windows cmd shell.

Cursorial CD Cursorial CD, or ccd for short, is a cd replacement for Window's cmd shell. Unlike cd, it operates on an edge first search, so you can qu

Scott Seligman 5 Feb 2, 2022
Notepad++ is a free source code editor and Notepad replacement that supports several programming languages and natural languages

Npp / Notepad++ is my customized text editor highly enhanced for coding such as insta-run, much more file extensions made self-recognizable, logically colored syntax highlighting for nearly every programming language and designed for very easy customizability -- from the toolbar, context menu, syntax coloring, plug-ins for optional increased capabilities and much more

SkyN9ne 1 Jan 23, 2022
A modern and functional replacement for the About Windows dialog

Modern Winver A modern and more functional replacement for the About Windows screen powered by UWP and RegistryRT, providing details on Windows and yo

Torch 146 Nov 26, 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 221 Nov 26, 2022