mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-09-16 19:02:05 +00:00
Merge branch 'main' into mk-localization
This commit is contained in:
@@ -23,13 +23,28 @@ const log = std.log.scoped(.i18n);
|
||||
///
|
||||
/// 3. Most preferred locale for a language without a country code.
|
||||
///
|
||||
/// Note for "most common" locales, this is subjective and based on
|
||||
/// the perceived userbase of Ghostty, which may not be representative
|
||||
/// of general populations or global language distribution. Also note
|
||||
/// that ordering may be weird when we first merge a new locale since
|
||||
/// we don't have a good way to determine this. We can always reorder
|
||||
/// with some data.
|
||||
pub const locales = [_][:0]const u8{
|
||||
"de_DE.UTF-8",
|
||||
"zh_CN.UTF-8",
|
||||
"de_DE.UTF-8",
|
||||
"fr_FR.UTF-8",
|
||||
"ja_JP.UTF-8",
|
||||
"nl_NL.UTF-8",
|
||||
"nb_NO.UTF-8",
|
||||
"ru_RU.UTF-8",
|
||||
"uk_UA.UTF-8",
|
||||
"pl_PL.UTF-8",
|
||||
"mk_MK.UTF-8",
|
||||
"tr_TR.UTF-8",
|
||||
"id_ID.UTF-8",
|
||||
"es_BO.UTF-8",
|
||||
"pt_BR.UTF-8",
|
||||
"ca_ES.UTF-8",
|
||||
};
|
||||
|
||||
/// Set for faster membership lookup of locales.
|
||||
@@ -108,6 +123,9 @@ pub fn canonicalizeLocale(
|
||||
buf: []u8,
|
||||
locale: []const u8,
|
||||
) error{NoSpaceLeft}![:0]const u8 {
|
||||
// Fix zh locales for macOS
|
||||
if (fixZhLocale(locale)) |fixed| return fixed;
|
||||
|
||||
// Buffer must be 16 or at least as long as the locale and null term
|
||||
if (buf.len < @max(16, locale.len + 1)) return error.NoSpaceLeft;
|
||||
|
||||
@@ -126,6 +144,30 @@ pub fn canonicalizeLocale(
|
||||
return buf[0..slice.len :0];
|
||||
}
|
||||
|
||||
/// Handles some zh locales canonicalization because internal libintl
|
||||
/// canonicalization function doesn't handle correctly in these cases.
|
||||
fn fixZhLocale(locale: []const u8) ?[:0]const u8 {
|
||||
var it = std.mem.splitScalar(u8, locale, '-');
|
||||
const name = it.next() orelse return null;
|
||||
if (!std.mem.eql(u8, name, "zh")) return null;
|
||||
|
||||
const script = it.next() orelse return null;
|
||||
const region = it.next() orelse return null;
|
||||
|
||||
if (std.mem.eql(u8, script, "Hans")) {
|
||||
if (std.mem.eql(u8, region, "SG")) return "zh_SG";
|
||||
return "zh_CN";
|
||||
}
|
||||
|
||||
if (std.mem.eql(u8, script, "Hant")) {
|
||||
if (std.mem.eql(u8, region, "MO")) return "zh_MO";
|
||||
if (std.mem.eql(u8, region, "HK")) return "zh_HK";
|
||||
return "zh_TW";
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// This can be called at any point a compile-time-known locale is
|
||||
/// available. This will use comptime to verify the locale is supported.
|
||||
pub fn staticLocale(comptime v: [*:0]const u8) [*:0]const u8 {
|
||||
@@ -160,6 +202,12 @@ test "canonicalizeLocale darwin" {
|
||||
try testing.expectEqualStrings("zh_CN", try canonicalizeLocale(&buf, "zh-Hans"));
|
||||
try testing.expectEqualStrings("zh_TW", try canonicalizeLocale(&buf, "zh-Hant"));
|
||||
|
||||
try testing.expectEqualStrings("zh_CN", try canonicalizeLocale(&buf, "zh-Hans-CN"));
|
||||
try testing.expectEqualStrings("zh_SG", try canonicalizeLocale(&buf, "zh-Hans-SG"));
|
||||
try testing.expectEqualStrings("zh_TW", try canonicalizeLocale(&buf, "zh-Hant-TW"));
|
||||
try testing.expectEqualStrings("zh_HK", try canonicalizeLocale(&buf, "zh-Hant-HK"));
|
||||
try testing.expectEqualStrings("zh_MO", try canonicalizeLocale(&buf, "zh-Hant-MO"));
|
||||
|
||||
// This is just an edge case I want to make sure we're aware of:
|
||||
// canonicalizeLocale does not handle encodings and will turn them into
|
||||
// underscores. We should parse them out before calling this function.
|
||||
|
||||
@@ -25,9 +25,9 @@ const c = if (builtin.os.tag != .windows) @cImport({
|
||||
// Entry that is retrieved from the passwd API. This only contains the fields
|
||||
// we care about.
|
||||
pub const Entry = struct {
|
||||
shell: ?[]const u8 = null,
|
||||
home: ?[]const u8 = null,
|
||||
name: ?[]const u8 = null,
|
||||
shell: ?[:0]const u8 = null,
|
||||
home: ?[:0]const u8 = null,
|
||||
name: ?[:0]const u8 = null,
|
||||
};
|
||||
|
||||
/// Get the passwd entry for the currently executing user.
|
||||
@@ -117,30 +117,27 @@ pub fn get(alloc: Allocator) !Entry {
|
||||
|
||||
// Shell and home are the last two entries
|
||||
var it = std.mem.splitBackwardsScalar(u8, std.mem.trimRight(u8, output, " \r\n"), ':');
|
||||
result.shell = it.next() orelse null;
|
||||
result.home = it.next() orelse null;
|
||||
result.shell = if (it.next()) |v| try alloc.dupeZ(u8, v) else null;
|
||||
result.home = if (it.next()) |v| try alloc.dupeZ(u8, v) else null;
|
||||
return result;
|
||||
}
|
||||
|
||||
if (pw.pw_shell) |ptr| {
|
||||
const source = std.mem.sliceTo(ptr, 0);
|
||||
const sh = try alloc.alloc(u8, source.len);
|
||||
@memcpy(sh, source);
|
||||
result.shell = sh;
|
||||
const value = try alloc.dupeZ(u8, source);
|
||||
result.shell = value;
|
||||
}
|
||||
|
||||
if (pw.pw_dir) |ptr| {
|
||||
const source = std.mem.sliceTo(ptr, 0);
|
||||
const dir = try alloc.alloc(u8, source.len);
|
||||
@memcpy(dir, source);
|
||||
result.home = dir;
|
||||
const value = try alloc.dupeZ(u8, source);
|
||||
result.home = value;
|
||||
}
|
||||
|
||||
if (pw.pw_name) |ptr| {
|
||||
const source = std.mem.sliceTo(ptr, 0);
|
||||
const name = try alloc.alloc(u8, source.len);
|
||||
@memcpy(name, source);
|
||||
result.name = name;
|
||||
const value = try alloc.dupeZ(u8, source);
|
||||
result.name = value;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -23,6 +23,8 @@ pub fn ShellEscapeWriter(comptime T: type) type {
|
||||
'?',
|
||||
' ',
|
||||
'|',
|
||||
'(',
|
||||
')',
|
||||
=> &[_]u8{ '\\', byte },
|
||||
else => &[_]u8{byte},
|
||||
};
|
||||
@@ -93,3 +95,12 @@ test "shell escape 6" {
|
||||
try writer.writeAll("a\"c");
|
||||
try testing.expectEqualStrings("a\\\"c", fmt.getWritten());
|
||||
}
|
||||
|
||||
test "shell escape 7" {
|
||||
var buf: [128]u8 = undefined;
|
||||
var fmt = std.io.fixedBufferStream(&buf);
|
||||
var shell: ShellEscapeWriter(@TypeOf(fmt).Writer) = .{ .child_writer = fmt.writer() };
|
||||
const writer = shell.writer();
|
||||
try writer.writeAll("a(1)");
|
||||
try testing.expectEqualStrings("a\\(1\\)", fmt.getWritten());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user