LeviLamina
Loading...
Searching...
No Matches
I18n.h
1#pragma once
2
3#include "ll/api/Expected.h"
4#include "ll/api/base/Concepts.h"
5#include "ll/api/base/FixedString.h"
6
7#if LL_HAS_CXX23
8#include <expected>
9#endif
10
11#include "fmt/args.h" // IWYU pragma: keep
12#include "fmt/chrono.h" // IWYU pragma: keep
13#include "fmt/color.h" // IWYU pragma: keep
14#include "fmt/compile.h" // IWYU pragma: keep
15#include "fmt/format.h" // IWYU pragma: keep
16#include "fmt/os.h" // IWYU pragma: keep
17#include "fmt/ranges.h" // IWYU pragma: keep
18#include "fmt/std.h" // IWYU pragma: keep
19
20// #define LL_I18N_COLLECT_STRINGS
21
22namespace ll::i18n {
23
24LLNDAPI std::string_view getDefaultLocaleCode();
25
26class I18n {
27 struct Impl;
28 std::unique_ptr<Impl> impl;
29
30public:
31 LLNDAPI I18n();
32 LLAPI ~I18n();
33
34 LLNDAPI Expected<> load(std::filesystem::path const& path) noexcept;
35
36 LLAPI void clear();
37
38 LLAPI void set(std::string_view localeCode, std::string_view key, std::string_view value);
39
40 LLNDAPI std::string_view get(std::string_view key, std::string_view localeCode) const;
41};
42
43inline I18n& getInstance() {
44 static I18n ins{};
45 return ins;
46}
47
48class I18nStringError : public ErrorInfoBase {
49private:
50 gsl::not_null<I18n*> mI18n;
51 std::string mKey;
52 fmt::dynamic_format_arg_store<fmt::format_context> mArgs;
53
54public:
55 template <typename... Args>
56 constexpr explicit I18nStringError(fmt::format_string<Args...> fmt, Args&&... args)
57 : mI18n(std::addressof(ll::i18n::getInstance())),
58 mKey(std::string{fmt.get().begin(), fmt.get().end()}),
59 mArgs() {
60 if constexpr (sizeof...(Args) > 0) {
61 mArgs.reserve(sizeof...(Args), 0);
62 (mArgs.push_back(std::forward<Args>(args)), ...);
63 }
64 }
65
66public:
67 std::string message() const noexcept override { return message(ll::i18n::getDefaultLocaleCode()); }
68 std::string message(std::string_view localeCode) const noexcept override try {
69 auto pattern = mI18n->get(mKey, localeCode.empty() ? ll::i18n::getDefaultLocaleCode() : localeCode);
70 if (!pattern.empty()) try {
71 return fmt::vformat(pattern, mArgs);
72 } catch (...) {}
73 return fmt::vformat(mKey, mArgs);
74 } catch (...) {
75 return mKey;
76 }
77
78 std::string const& key() const noexcept { return mKey; }
79 fmt::dynamic_format_arg_store<fmt::format_context> const& args() const noexcept { return mArgs; }
80};
81
82} // namespace ll::i18n
83
84#ifdef LL_I18N_COLLECT_STRINGS
85#include "ll/api/reflection/TypeName.h"
86
87#ifndef LL_I18N_STRING_LITERAL_TYPE
88#define LL_I18N_STRING_LITERAL_TYPE ::ll::FixedStrWithLoc
89#endif
90
91namespace ll::i18n::detail {
92template <LL_I18N_STRING_LITERAL_TYPE str>
93struct TrStrOut;
94#ifndef LL_I18N_COLLECT_STRINGS_CUSTOM
95template <LL_I18N_STRING_LITERAL_TYPE str>
96struct TrStrOut {
97 static inline int _ = [] {
98 fmt::print("\"{0}\": \"{0}\", // at {1}\n", str.sv(), str.loc().toString());
99 return 0;
100 }();
101};
102#endif
103} // namespace ll::i18n::detail
104#else
105#ifndef LL_I18N_STRING_LITERAL_TYPE
106#define LL_I18N_STRING_LITERAL_TYPE ::ll::FixedString
107#endif
108#endif
109
110namespace ll {
111template <LL_I18N_STRING_LITERAL_TYPE Fmt, typename... Args>
112[[nodiscard]] inline Unexpected makeI18nStringError(Args&&... args) noexcept {
113#ifdef LL_I18N_COLLECT_STRINGS
114 static i18n::detail::TrStrOut<Fmt> e{};
115#endif
116 return makeError<i18n::I18nStringError>(fmt::format_string<Args...>(Fmt.sv()), std::forward<Args>(args)...);
117}
118} // namespace ll
119
120namespace ll::inline literals::inline i18n_literals {
121template <LL_I18N_STRING_LITERAL_TYPE Fmt>
122[[nodiscard]] constexpr auto operator""_tr() {
123#ifdef LL_I18N_COLLECT_STRINGS
124 static i18n::detail::TrStrOut<Fmt> e{};
125#endif
126 return [=]<class... Args>(Args&&... args) {
127 [[maybe_unused]] static constexpr auto checker = fmt::format_string<Args...>(Fmt.sv());
128 return fmt::vformat(i18n::getInstance().get(Fmt.sv(), {}), fmt::make_format_args(args...));
129 };
130}
131template <LL_I18N_STRING_LITERAL_TYPE Fmt>
132[[nodiscard]] constexpr auto operator""_trl() {
133#ifdef LL_I18N_COLLECT_STRINGS
134 static i18n::detail::TrStrOut<Fmt> e{};
135#endif
136 return [=]<class... Args>(std::string_view localeCode, Args&&... args) {
137 [[maybe_unused]] static constexpr auto checker = fmt::format_string<Args...>(Fmt.sv());
138 return fmt::vformat(i18n::getInstance().get(Fmt.sv(), localeCode), fmt::make_format_args(args...));
139 };
140}
141} // namespace ll::inline literals::inline i18n_literals
Definition I18n.h:26